Last Updated: 2026-04-03 Status: Draft
1. Service Overview
| Property | Value |
|---|---|
| Service Owner | apps/contact-intelligence |
| Base URL | https://api.logicspike.com/contact-intel (via Gateway) |
| Internal Microservice | contact-intelligence.logicspike.workers.dev |
| Gateway Key Header | x-gateway-key |
| Primary Consumer | Chat Engine (service-to-service) |
| Secondary Consumer | AI Brain (via brain tools) |
2. Authentication Requirements
| Domain | Auth Type | Header | Consumer |
|---|---|---|---|
| Context Retrieval | Gateway key | x-gateway-key |
Chat Engine |
| Ingestion | Gateway key | x-gateway-key |
Chat Engine |
| Contact Management | JWT (user session) | Authorization: Bearer <token> |
AI Brain / Dashboard |
| Outreach Management | JWT (user session) | Authorization: Bearer <token> |
AI Brain / Dashboard |
| Analytics | JWT (user session) | Authorization: Bearer <token> |
AI Brain |
| Internal (Cron, Queues) | Gateway key | x-gateway-key |
CF Cron / CF Queues |
3. Endpoints by Domain
3.1 Context & Ingestion (Chat Engine — Hot Path)
🔍 Get Contact Context
The primary hot-path endpoint. Called by Chat Engine on every incoming message. Returns memories, emotional state, and relationship context for a contact.
GET /contact-intel/context/:contact_id
x-gateway-key: <key>Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
message |
String | ❌ | Current user message (used for mood classification and memory relevance scoring) |
memory_limit |
Integer | 10 | Max memories to return |
min_importance |
Float | 0.3 | Minimum importance threshold for memories |
Response:
{
"contact": {
"id": "ct_arjun",
"display_name": "Arjun",
"language": "en",
"channel": "whatsapp"
},
"state": {
"mood": "neutral",
"energy": "medium",
"conversation_style": "playful",
"relationship_stage": "established",
"active_streak": 20,
"total_messages": 245,
"total_sessions": 22,
"last_active_at": "2026-04-02T22:30:00Z"
},
"memories": [
{
"id": "mem_001",
"type": "fact",
"content": "Has a golden retriever named Bruno",
"importance": 0.88,
"entity_ids": ["pet:bruno"],
"retrieval_score": 0.92
},
{
"id": "mem_002",
"type": "preference",
"content": "Likes playful banter and humor",
"importance": 0.80,
"entity_ids": [],
"retrieval_score": 0.78
}
],
"relationship": {
"days_since_first_contact": 20,
"stage": "established",
"trust_level": "high"
}
}Error Codes:
| Code | HTTP | Description |
|---|---|---|
CONTACT_NOT_FOUND |
404 | Contact ID does not exist for this tenant |
Performance SLA: < 30ms p95
📥 Ingest Interaction
Called by Chat Engine after generating a response. Triggers memory extraction, mood update, and deferred processing.
POST /contact-intel/ingest
x-gateway-key: <key>
Content-Type: application/jsonRequest Body:
{
"tenant_id": "tnt_ravi",
"contact_id": "ct_arjun",
"user_message": "Ugh, Bruno ate my shoes again",
"ai_response": "Nooo not again! Bruno has a shoe addiction at this point...",
"detected_mood": "frustrated",
"detected_energy": "medium",
"session_id": "sess_abc123"
}| Field | Type | Required | Description |
|---|---|---|---|
tenant_id |
UUID | ✅ | Business tenant |
contact_id |
UUID | ✅ | End-user contact |
user_message |
String | ✅ | The user's message |
ai_response |
String | ✅ | The AI's generated response |
detected_mood |
Enum | ❌ | Pre-classified mood (if Chat Engine classified it). If omitted, Contact Intelligence classifies. |
detected_energy |
Enum | ❌ | Pre-classified energy |
session_id |
UUID | ✅ | Groups messages into sessions |
Response:
{
"status": "accepted",
"memories_extracted": 2,
"state_updated": true,
"triggers_created": 0,
"deferred_tasks_queued": 3
}Performance SLA: < 50ms (returns 202 Accepted, deferred work is async)
➕ Create Contact
Creates a new contact profile. Called by Chat Engine on first interaction from an unknown external ID.
POST /contact-intel/contacts
x-gateway-key: <key>
Content-Type: application/jsonRequest Body:
{
"tenant_id": "tnt_ravi",
"external_id": "wa_919876543210",
"channel": "whatsapp",
"display_name": "Arjun"
}Response:
{
"id": "ct_arjun",
"tenant_id": "tnt_ravi",
"external_id": "wa_919876543210",
"channel": "whatsapp",
"display_name": "Arjun",
"state": {
"mood": "neutral",
"energy": "medium",
"conversation_style": "casual",
"relationship_stage": "new",
"active_streak": 0,
"total_messages": 0
},
"created_at": "2026-04-03T22:15:00Z"
}3.2 Contact Management (AI Brain / Dashboard)
📋 List Contacts
GET /contact-intel/contacts?sort=engagement&stage=established&limit=20Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
sort |
Enum | recent |
recent, engagement, churn_risk, messages |
stage |
Enum | all |
Filter: new, building, established, deep, fading, dormant, all |
churn_risk_min |
Float | ❌ | Filter contacts above this churn risk |
limit |
Integer | 20 | Max results (1–100) |
offset |
Integer | 0 | Pagination offset |
Response:
{
"contacts": [
{
"id": "ct_arjun",
"display_name": "Arjun",
"channel": "whatsapp",
"relationship_stage": "established",
"active_streak": 20,
"total_messages": 245,
"churn_risk": 0.12,
"mood": "happy",
"last_active_at": "2026-04-02T22:30:00Z"
}
],
"total": 234,
"limit": 20,
"offset": 0
}👤 Get Contact Profile
Full profile including memories, state, entities, and recent triggers.
GET /contact-intel/contacts/:id/profileResponse:
{
"contact": {
"id": "ct_arjun",
"display_name": "Arjun",
"channel": "whatsapp",
"language": "en",
"created_at": "2026-03-15T22:15:00Z"
},
"state": {
"mood": "happy",
"energy": "high",
"relationship_stage": "established",
"active_streak": 20,
"total_messages": 245,
"total_sessions": 22,
"churn_risk": 0.12,
"preferred_hours": ["22:00", "23:00"]
},
"memories": {
"total": 48,
"by_type": { "fact": 15, "preference": 8, "episode": 20, "pattern": 5 },
"top": [
{ "type": "fact", "content": "Software engineer at Infosys", "importance": 0.85 },
{ "type": "fact", "content": "Has a golden retriever named Bruno", "importance": 0.88 },
{ "type": "pattern", "content": "Usually chats between 10pm-12am", "importance": 0.75 }
]
},
"entities": [
{ "id": "pet:bruno", "type": "pet", "display_name": "Bruno", "memory_count": 12 },
{ "id": "workplace:infosys", "type": "workplace", "display_name": "Infosys", "memory_count": 5 }
],
"recent_outreach": [
{ "type": "scheduled", "message": "Good morning! Hope the presentation goes well...", "sent_at": "2026-04-01T08:00:00Z", "status": "sent" }
]
}🗑️ Delete Contact (GDPR)
Deletes a contact and ALL associated data (memories, state, triggers, logs).
DELETE /contact-intel/contacts/:idResponse:
{
"status": "deleted",
"deleted": {
"memories": 48,
"entities": 7,
"triggers": 3,
"interaction_logs": 245
}
}📦 Export Contact Data (GDPR)
GET /contact-intel/contacts/:id/exportResponse: Full JSON export of all contact data — profile, state, memories, entities, triggers, interaction logs.
3.3 Outreach Management
📨 Schedule Outreach
Manually schedule a proactive message to a contact.
POST /contact-intel/outreach
Content-Type: application/jsonRequest Body:
{
"contact_id": "ct_arjun",
"trigger_type": "scheduled",
"channel": "whatsapp",
"generate_with_llm": true,
"llm_context": "Arjun was upset about missing a promotion. Send a supportive check-in.",
"scheduled_at": "2026-04-04T08:00:00Z"
}Response:
{
"id": "trg_789",
"status": "pending",
"scheduled_at": "2026-04-04T08:00:00Z",
"will_generate": true
}📋 List Outreach Triggers
GET /contact-intel/outreach?contact_id=ct_arjun&status=pendingQuery Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
contact_id |
UUID | ❌ | Filter by contact |
status |
Enum | all |
pending, sent, failed, cancelled, all |
trigger_type |
Enum | all |
scheduled, inactivity, milestone, recurring, all |
limit |
Integer | 20 | Max results |
❌ Cancel Outreach Trigger
POST /contact-intel/outreach/:id/cancelResponse:
{
"status": "cancelled",
"trigger_id": "trg_789"
}⚙️ Get Outreach Config
GET /contact-intel/outreach/configResponse:
{
"inactivity_enabled": true,
"inactivity_days": 3,
"inactivity_max_attempts": 2,
"milestone_enabled": true,
"recurring_enabled": false,
"recurring_cron": null,
"quiet_hours_start": "23:00",
"quiet_hours_end": "07:00"
}⚙️ Update Outreach Config
PATCH /contact-intel/outreach/config
Content-Type: application/jsonRequest Body:
{
"inactivity_days": 5,
"recurring_enabled": true,
"recurring_cron": "0 8 * * *",
"quiet_hours_start": "22:00"
}3.4 Analytics (AI Brain)
📊 Get Engagement Trends
GET /contact-intel/analytics/trends?days=7Response:
{
"period_days": 7,
"active_users": 234,
"active_users_change": 0.12,
"new_users": 28,
"churned_users": 3,
"total_messages": 8400,
"avg_session_duration_min": 23,
"avg_messages_per_session": 18,
"retention_7day": 0.82,
"retention_30day": 0.58,
"daily": [
{ "date": "2026-04-01", "active": 198, "new": 5, "messages": 1150 },
{ "date": "2026-04-02", "active": 210, "new": 4, "messages": 1230 }
]
}⚠️ Get Churn Risk Report
GET /contact-intel/analytics/churn?threshold=0.6&limit=20Response:
{
"threshold": 0.6,
"at_risk_count": 8,
"contacts": [
{
"id": "ct_deepak",
"display_name": "Deepak",
"churn_risk": 0.89,
"last_active_at": "2026-03-29T18:00:00Z",
"days_inactive": 5,
"relationship_stage": "fading",
"last_mood": "bored",
"outreach_status": "none_sent"
}
]
}😊 Get Mood Distribution
GET /contact-intel/analytics/moods?days=7Response:
{
"period_days": 7,
"total_classifications": 8400,
"distribution": {
"happy": 0.35,
"neutral": 0.28,
"excited": 0.12,
"playful": 0.08,
"sad": 0.06,
"anxious": 0.04,
"frustrated": 0.04,
"bored": 0.02,
"angry": 0.01
},
"trend": "positive"
}3.5 Memory Management
🧠 List Contact Memories
GET /contact-intel/contacts/:id/memories?type=fact&limit=20Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
type |
Enum | all |
fact, preference, episode, pattern, all |
min_importance |
Float | 0.0 | Minimum importance threshold |
entity |
String | ❌ | Filter by entity ID (e.g., pet:bruno) |
limit |
Integer | 20 | Max results |
🗑️ Delete Memory
Allows business owner (via Brain) or contact ("forget this") to delete a specific memory.
DELETE /contact-intel/contacts/:id/memories/:memory_id🗑️ Delete All Memories (Forget Me)
Complete memory wipe for a contact.
DELETE /contact-intel/contacts/:id/memoriesResponse:
{
"status": "deleted",
"memories_deleted": 48,
"entities_deleted": 7,
"state_reset": true
}3.6 Internal Endpoints (Cron & Queue)
⏰ Fire Outreach Triggers (Cron)
POST /internal/outreach/fire
x-gateway-key: <key>Called every 15 minutes by Cron Trigger. Scans for pending triggers whose scheduled_at has passed, inactivity thresholds reached, or milestones hit.
🔄 Process Deferred Consolidation (Queue Consumer)
POST /internal/memory/consolidate
x-gateway-key: <key>Request Body (from CF Queue):
{
"tenant_id": "tnt_ravi",
"contact_id": "ct_arjun",
"tasks": ["embed_memories", "merge_duplicates", "extract_entities", "check_triggers"]
}📉 Run Churn Scoring & Memory Decay (Cron)
POST /internal/maintenance
x-gateway-key: <key>Called every 6 hours. Recomputes churn_risk for all active contacts, decays unaccessed memories, prunes low-importance memories.
4. Generic Error Response Format
{
"error": {
"code": "CONTACT_NOT_FOUND",
"message": "Contact ct_xyz does not exist for this tenant.",
"details": {}
}
}Standard Error Codes:
| Code | HTTP | Description |
|---|---|---|
CONTACT_NOT_FOUND |
404 | Contact ID does not exist for this tenant |
OUTREACH_DISABLED |
409 | Contact has outreach disabled — cannot schedule triggers |
TRIGGER_NOT_FOUND |
404 | Outreach trigger ID does not exist |
RATE_LIMITED |
429 | Too many requests to this endpoint |
INVALID_INPUT |
400 | Malformed request body |
PERMISSION_DENIED |
403 | User lacks required PBAC permission |
QUIET_HOURS |
409 | Cannot schedule outreach during configured quiet hours |
MAX_ATTEMPTS_REACHED |
409 | Inactivity outreach limit already reached for this contact |