Skip to main content

CRM (Customer Relationship Management)

The Ravenmask CRM is a lightweight customer lifecycle management system for tracking leads, accounts, and sales opportunities.

Overview

ComponentURLDescription
Web UIhttps://crm.ravenhelm.devMain CRM interface
APIhttps://crm.ravenhelm.dev/api/v1REST API
API Docshttps://crm.ravenhelm.dev/api/docsSwagger documentation

Architecture

Frontend (React)  -->  Backend (FastAPI)  -->  PostgreSQL (crm db)
|
v
Traefik (*.ravenhelm.dev)
^
|
Bifrost MCP --> Norns Agent

Stack:

  • Frontend: React + TypeScript + Vite + TanStack Query
  • Backend: Python + FastAPI + SQLAlchemy
  • Database: PostgreSQL (crm database)
  • Proxy: Traefik
  • MCP Integration: Bifrost (CRM executor)

Data Model

Leads

Pre-qualified prospects. Flow: New -> Contacted -> Qualified -> Converted

FieldDescription
first_name, last_nameContact name (required)
email, phoneContact info
company, titleCompany details
statusnew, contacted, qualified, unqualified, converted
sourceOrigin (website, linkedin, referral, etc.)
estimated_valuePotential deal size
notesFree-form notes

Accounts

Companies/organizations you do business with.

FieldDescription
nameCompany name (required)
domainWebsite domain
industryIndustry sector
segmentSMB, Mid-Market, Enterprise

Opportunities

Active deals in the sales pipeline.

FieldDescription
nameDeal name (required)
account_idLinked account
stagePipeline stage (Lead -> Discovery -> Proposal -> Negotiation -> Closed Won/Lost)
amountDeal value
close_dateExpected close date
probabilityWin probability (0-100%)
pipeline_idWhich pipeline this belongs to

Pipeline Stages (Default)

  1. Lead (10%)
  2. Discovery (25%)
  3. Proposal (50%)
  4. Negotiation (75%)
  5. Closed Won (100%)
  6. Closed Lost (0%)

MCP Tools (Bifrost)

The CRM is integrated with Bifrost MCP, allowing AI agents (like Norns) to interact with CRM data programmatically.

Available Tools

Lead Management

ToolDescription
crm_list_leadsList all leads, optionally filter by status
crm_get_leadGet details of a specific lead by UUID
crm_create_leadCreate a new lead (requires first_name, last_name)
crm_update_leadUpdate lead fields or status
crm_convert_leadConvert qualified lead to opportunity

Account Management

ToolDescription
crm_list_accountsList all accounts, optionally search by name
crm_get_accountGet account details including linked opportunities
crm_create_accountCreate a new account (requires name)
crm_update_accountUpdate account fields

Opportunity Management

ToolDescription
crm_list_opportunitiesList opportunities, filter by account/stage/pipeline
crm_get_opportunityGet opportunity details
crm_create_opportunityCreate a new opportunity (requires name)
crm_update_opportunityUpdate opportunity stage, amount, or close date

Pipeline

ToolDescription
crm_get_pipelineGet pipeline stages configuration
crm_get_pipeline_summaryGet pipeline summary with counts and values per stage

Tool Parameters

crm_create_lead

{
"first_name": "John", // required
"last_name": "Doe", // required
"email": "john@example.com",
"phone": "+1-555-1234",
"company": "Acme Corp",
"title": "CTO",
"source": "linkedin",
"estimated_value": "$50,000",
"notes": "Met at conference"
}

crm_update_lead

{
"lead_id": "uuid", // required
"status": "qualified", // new, contacted, qualified, unqualified
"notes": "Follow up scheduled"
}

crm_convert_lead

{
"lead_id": "uuid", // required
"opportunity_name": "Acme Corp - Enterprise Deal",
"amount": 50000,
"close_date": "2025-03-31",
"create_account": true // create account from company name
}

crm_create_opportunity

{
"name": "New Deal", // required
"account_id": "uuid",
"stage": "Discovery",
"amount": 25000,
"close_date": "2025-06-30",
"probability": 25
}

crm_get_pipeline_summary

Returns pipeline overview:

{
"pipeline_id": "uuid",
"stages": {
"Lead": {"count": 5, "value": 100000, "weighted_value": 10000, "probability": 10},
"Discovery": {"count": 3, "value": 75000, "weighted_value": 18750, "probability": 25},
"Proposal": {"count": 2, "value": 50000, "weighted_value": 25000, "probability": 50}
},
"totals": {
"opportunities": 10,
"pipeline_value": 225000,
"weighted_value": 53750
}
}

Example Agent Interactions

List qualified leads:

"Show me all qualified leads"

Tool: crm_list_leads
Args: {"status": "qualified"}

Create a lead from a conversation:

"Add a lead for Sarah Chen from TechCorp, she's interested in our enterprise plan"

Tool: crm_create_lead
Args: {
"first_name": "Sarah",
"last_name": "Chen",
"company": "TechCorp",
"source": "conversation",
"notes": "Interested in enterprise plan"
}

Get pipeline status:

"What does our sales pipeline look like?"

Tool: crm_get_pipeline_summary
Args: {}

Advance an opportunity:

"Move the TechCorp deal to proposal stage"

Tool: crm_update_opportunity
Args: {"opportunity_id": "uuid", "stage": "Proposal"}

Implementation Details

  • Executor: ~/ravenhelm/services/bifrost/api/executors/crm.py
  • Executor Type: crm
  • Internal URL: http://crm-backend:8000 (Docker network)
  • Tools registered in: tool_definitions table (ravenmaskos database)

Webhooks API

Public endpoints for external integrations (marketing forms, LinkedIn, etc.)

Create Single Lead

Endpoint: POST /api/v1/webhooks/leads

Request:

{
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1-555-1234",
"company": "Acme Corp",
"title": "CTO",
"source": "linkedin",
"source_detail": "Q1 Lead Gen Campaign",
"estimated_value": "$50,000",
"notes": "Met at AWS re:Invent"
}

Response:

{
"success": true,
"lead_id": "uuid-here",
"message": "Lead created: John Doe"
}

Create Multiple Leads (Batch)

Endpoint: POST /api/v1/webhooks/leads/batch

Request:

{
"leads": [
{"first_name": "Jane", "last_name": "Smith", "email": "jane@corp.com", "source": "trade_show"},
{"first_name": "Bob", "last_name": "Wilson", "email": "bob@inc.com", "source": "trade_show"}
]
}

Response:

{
"success": true,
"total": 2,
"created": 2,
"failed": 0,
"lead_ids": ["uuid-1", "uuid-2"],
"errors": null
}

Webhook Fields Reference

FieldRequiredTypeDescription
first_nameYesstringFirst name (max 100 chars)
last_nameYesstringLast name (max 100 chars)
emailNostringEmail address
phoneNostringPhone number
companyNostringCompany name
titleNostringJob title
sourceNostringLead source identifier
source_detailNostringCampaign name, form ID, etc.
estimated_valueNostringPotential deal size
notesNostringAdditional notes
custom_dataNoobjectAny extra JSON fields

Optional Headers

HeaderDescription
X-SourceOverride lead source for all leads in request
X-Webhook-SignatureHMAC-SHA256 signature for security verification

Common Source Values

SourceUse Case
websiteContact forms on website
linkedinLinkedIn Lead Gen Forms
referralCustomer/partner referrals
trade_showConference badge scans
cold_callOutbound prospecting
email_campaignMarketing email responses
social_mediaSocial media inquiries
webinarWebinar registrations

Integration Examples

cURL

curl -X POST https://crm.ravenhelm.dev/api/v1/webhooks/leads \
-H "Content-Type: application/json" \
-d '{
"first_name": "Test",
"last_name": "Lead",
"email": "test@example.com",
"source": "api_test"
}'

n8n Workflow

Use HTTP Request node:

  • Method: POST
  • URL: https://crm.ravenhelm.dev/api/v1/webhooks/leads
  • Headers: Content-Type: application/json
  • Body: JSON with lead fields

JavaScript/Fetch

await fetch('https://crm.ravenhelm.dev/api/v1/webhooks/leads', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
source: 'website_form'
})
});

Python

import requests

response = requests.post(
'https://crm.ravenhelm.dev/api/v1/webhooks/leads',
json={
'first_name': 'John',
'last_name': 'Doe',
'email': 'john@example.com',
'source': 'python_script'
}
)
print(response.json())

Service Management

Location

odin:/Users/ravenhelm/ravenhelm/services/crm/
├── backend/ # FastAPI application
├── frontend/ # React application
└── docker-compose.yml

Commands

# View logs
ssh ravenhelm@100.115.101.81 "docker logs -f crm-backend"
ssh ravenhelm@100.115.101.81 "docker logs -f crm-frontend"

# Restart services
ssh ravenhelm@100.115.101.81 "cd ~/ravenhelm/services/crm && docker compose restart"

# Rebuild after code changes
ssh ravenhelm@100.115.101.81 "cd ~/ravenhelm/services/crm && docker compose build && docker compose up -d"

Database

# Connect to CRM database
ssh ravenhelm@100.115.101.81 "docker exec -it postgres psql -U ravenhelm -d crm"

# Check data counts
ssh ravenhelm@100.115.101.81 "docker exec -i postgres psql -U ravenhelm -d crm -c \"
SELECT 'leads', COUNT(*) FROM leads
UNION ALL SELECT 'accounts', COUNT(*) FROM accounts
UNION ALL SELECT 'opportunities', COUNT(*) FROM opportunities;
\""

Workflows

Lead to Opportunity Conversion

  1. Lead enters system (webhook, manual, import)
  2. Sales qualifies lead (status: new -> contacted -> qualified)
  3. Convert qualified lead to opportunity
    • Creates opportunity in pipeline
    • Optionally creates account from company name
    • Links opportunity to account
  4. Work opportunity through pipeline stages
  5. Close won/lost

Creating Opportunities from Accounts

  1. Navigate to account detail page
  2. Click "New Opportunity"
  3. Fill in deal details
  4. Opportunity auto-linked to account

See Also