Open-Source Personal Networking CRM — AI-Powered, Self-Hostable
Auto-syncs Gmail, Telegram, Twitter/X, and LinkedIn. Detects life events. Drafts contextual follow-ups with AI. Tells you who to reach out to and why.
| Feature | PingCRM | Monica | Dex |
|---|---|---|---|
| Price | Free (self-hosted) | Free / $9/mo hosted | Free tier / $12/mo |
| AI message drafting | Yes | No | No |
| Gmail sync | Yes (threads) | No | Yes (contacts) |
| Telegram sync | Yes | No | No |
| Twitter/X sync | Yes (DMs + mentions) | No | Import only |
| LinkedIn sync | Yes (Chrome extension) | No | Yes |
| Relationship scoring | Yes (0–10) | No | Reminders only |
| Life event detection | Yes (multi-source) | Manual only | Job changes only |
| Identity resolution | Yes (4-tier) | No | Partial |
| Open source | Yes (AGPL-3.0) | Yes (AGPL-3.0) | No |
| Self-hostable | Yes | Yes | No |
- Features
- Tech Stack
- Prerequisites
- Setup Guide
- Environment Variables
- Project Structure
- API Reference
- Celery Beat Schedule
- Testing
The main screen provides a real-time overview of your networking activity:
- Total Contacts -- count of all contacts in your CRM
- Pending Suggestions -- follow-up suggestions awaiting your action
- Identity Matches -- potential duplicate contacts detected across platforms
- Reach Out This Week -- top 3 contacts recommended for follow-up, with reasons and AI-drafted messages
- Recent Activity -- contacts you've interacted with recently
- Relationship Health -- breakdown of contacts by status (active, warming, going cold)
- Paginated, sortable contact list with search
- Full-text search across contact names, emails, companies, Twitter handles, Telegram usernames, Twitter bios, Telegram bios, and interaction message content
- Sort by name, relationship score, or last interaction date
- Filter by tags
- Relationship strength color indicators (green/yellow/red)
- Avatar display with fallback initials
- Bulk actions -- multi-select contacts to add/remove tags, set priority level, set company, archive, merge, or delete
- Inline editing -- click any field to edit directly (name, email, company, title, phone, tags, notes, Twitter handle, Telegram username, LinkedIn URL)
- Company autocomplete -- when editing the Company field, search existing organizations with a dropdown. Select an org to link the contact, or type a new name
- Quick message composer -- always-visible collapsed bar above the timeline. Click to expand into a full message editor with channel selection (email, Telegram, Twitter)
- Interaction timeline -- chronological feed of all touchpoints across email, Telegram, Twitter, and manual notes, with platform icons and direction indicators. Bio changes appear as event pills in the timeline.
- Add manual notes -- record offline conversations or meetings
- Telegram common groups -- sidebar card showing shared Telegram groups with a contact (cached for 24 hours)
- Rate limit handling -- Telegram send shows countdown timer on 429 with Retry-After header
- Duplicate detection -- find and merge potential duplicate contacts
- Relationship score badge -- color-coded score with label (Active, Warm, Cooling, At Risk)
- Edit and delete notes -- hover pencil/trash icons on manual notes in the timeline
- Auto-sync on visit -- Telegram and Twitter messages sync automatically when viewing a contact
- Auto-dismiss suggestions -- pending follow-up suggestions dismissed when new interactions are synced
- Delete contact with confirmation dialog
- CSV upload -- drag-and-drop or file picker. Supports columns:
name,email,twitter,telegram,company,notes - Google Contacts sync -- one-click OAuth import of name, email, phone, company, and title
- Manual entry -- add contacts one at a time through the UI (
/contacts/new)
- OAuth 2.0 connection with Google
- Multi-account support -- connect multiple Google accounts
- Email sync -- imports email threads as interactions (sender, recipient, subject, timestamps, body snippets)
- Google Contacts sync -- one-way import of contacts from your Google address book
- Google Calendar sync -- imports calendar events as meeting interactions
- All syncs run as background Celery tasks with notification on completion or failure
- MTProto client integration (accesses your actual chat history, not bot API)
- Phone number + OTP verification flow
- Two-step verification (2FA) support for accounts with cloud passwords
- Chat sync -- imports DM conversations as interactions (skips unchanged dialogs to reduce API calls)
- Group member sync -- discovers contacts from shared Telegram groups
- Bio sync -- captures Telegram bios for your contacts (7-day freshness filter to reduce API calls)
- Common groups -- view which Telegram groups you share with a specific contact
- Rate gate -- Redis-based cross-operation coordination prevents FloodWaitError cascades
- Background sync with progress notifications
- OAuth 2.0 PKCE authentication flow
- Bird CLI (
@steipete/bird) -- cookie-based tweet/profile fetching bypassing API rate limits, with Twitter API as fallback - DM sync -- imports direct message conversations using per-conversation API (
/dm_conversations/with/:id) - Mention sync -- tracks @mentions and replies
- Bio monitoring -- detects bio changes (job changes, milestones), stores them as events, and adds them to the contact timeline
- Background sync with retry logic and failure notifications
- Companion Chrome extension (
chrome-extension/) for passive LinkedIn data capture - Profile sync -- captures name, headline, company, location, avatar when visiting profiles
- Message sync -- captures DM conversations from full-page messaging and overlay chat
- Avatar download -- high-res profile photos saved locally with SSRF domain allowlist
- Content-hash deduplication prevents duplicate messages
- Settings persist across browser sessions via chrome.storage.local
Automatically detects when contacts across different platforms are the same person:
- Tier 1: Deterministic matching (auto-merge) -- same email, same phone number, email found in Twitter bio
- Tier 2: Probabilistic matching (scored) -- weighted formula:
- Email domain match: 40%
- Name similarity: 20%
- Company match: 20%
- Username similarity: 10%
- Mutual signals: 10%
- Auto-merges above 85% confidence
- Colleague guard: caps score when names differ but company/email domain match (prevents false positives for coworkers)
- Tier 4: Manual review -- side-by-side comparison cards for low-confidence matches
- Merge or reject -- one-click actions to combine duplicate profiles or dismiss false matches
- Scan button -- trigger identity resolution on demand
Manage companies and organizations your contacts belong to:
- Flat table with sortable column headers (name, contacts, avg score, interactions, last activity)
- Click any column header to sort; active sort shows arrow indicator
- Domain favicon -- automatically fetches favicon from the org's domain as a logo
- Search -- filter organizations by name
- Select and merge -- checkbox selection with bulk merge for duplicate organizations
- Per-row delete -- trash icon on each row with confirmation dialog
- Bulk actions bar -- appears on selection with merge and delete options
- Pagination for large datasets
- Inline editing -- hover any field to reveal pencil icon, click to edit in place (name, location, website, LinkedIn, Twitter, notes)
- Stats cards -- contacts count, avg relationship score, total interactions, last activity (from materialized view, refreshed hourly)
- Contacts table -- sortable list of active contacts in the organization with score badges
- Auto-hidden -- organizations with zero active (non-archived) contacts are hidden from the list
- Delete organization -- unlinks contacts but does not delete them
AI-generated recommendations for who to reach out to and why:
- Time-based triggers -- no interaction in 90+ days, declining relationship score
- Event-based triggers -- detected job changes, fundraising announcements, product launches from Twitter activity
- Scheduled triggers -- user-set manual reminders with snooze reactivation
- AI message composer -- generates contextual draft messages using Claude 3.5 Haiku, considering:
- Contact profile (name, company, role)
- Last interaction summary and when it occurred
- Detected events (the reason for reaching out now)
- Conversation tone (formal vs. casual, based on past messages)
- Preferred channel (email, Telegram, Twitter)
- Actions per suggestion:
- Edit the AI-drafted message and mark as sent
- Snooze (2 weeks / 1 month / 3 months)
- Dismiss entirely
- Generate new suggestions on demand with one click
Automatic scoring of relationship health based on interaction patterns:
| Signal | Points |
|---|---|
| Message exchanged in last 30 days | +5 |
| Reply within 48 hours | +3 |
| Introduction or referral made | +2 |
| Mutual interaction (both sides initiate) | +2 |
| Per month of silence | -2 |
Score interpretation:
- 8+ (Green) -- Active relationship, no follow-up needed
- 4-7 (Yellow) -- Warm, could use a check-in soon
- 1-3 (Orange) -- Cooling off, follow-up recommended
- 0 or below (Red) -- At risk of going cold
Monitors Twitter activity from contacts and classifies events worth acting on:
| Event | Signal Source | Example |
|---|---|---|
| Job change | Twitter bio update, tweet | "Excited to join Stripe" |
| Fundraising | Tweet, email mention | "We just closed our seed round" |
| Product launch | Tweet | "We shipped today" |
| Promotion | Twitter bio | New title in bio |
| Personal milestone | Tweet | Wedding, move, new baby |
| Conference/event | Tweet, email | Speaking at or attending an event |
Uses Claude for LLM-powered event classification with confidence scoring.
In-app notification center for all system events:
- Sync completion and failure alerts
- New follow-up suggestion notifications
- Bio change detections
- Identity match discoveries
- Mark individual or all notifications as read
- Click any notification to navigate to the relevant page
- Unread badge in navigation
Central hub for managing all platform connections and data sync:
- Gmail -- connect/disconnect, view connected email, sync contacts, sync calendar events
- Telegram -- connect via phone number, OTP verification, 2FA support, sync chats
- Twitter -- OAuth connect/disconnect, sync DMs and mentions
- CSV Import -- upload contact spreadsheets with drag-and-drop
- Connection status badges showing connected accounts and usernames
Guided 4-step setup flow for new users:
- Welcome screen
- Connect Google account
- Import contacts
- Done -- redirects to dashboard
- Google OAuth -- sign in with Google account
- Email/password -- register and login with email
- JWT-based session management (24-hour token expiry)
- Protected routes with automatic redirect to login
- Global error boundary with recovery action
- 404 Not Found page
- Per-page error states with retry buttons
- Empty states with helpful guidance for new users
| Component | Technology |
|---|---|
| Backend | Python 3.12 + FastAPI |
| Database | PostgreSQL (via SQLAlchemy 2.x async + asyncpg) |
| Migrations | Alembic |
| Task Queue | Redis + Celery |
| AI | Anthropic Claude 3.5 Haiku (event classification + message composition) |
| Frontend | Next.js 15 + React 19 + Tailwind CSS v4 |
| State Management | TanStack React Query v5 |
| Telegram | Telethon (MTProto client) |
| Google APIs | google-api-python-client + google-auth-oauthlib |
| Auth | python-jose (JWT) + passlib (bcrypt) |
| HTTP Client | httpx (async) + openapi-fetch (frontend) |
| Testing | pytest (backend, 631 tests) + Vitest (frontend, 481 tests) |
- Python 3.12+
- Node.js 18+ and npm
- PostgreSQL 14+
- Redis 6+
git clone https://github.com/sneg55/pingcrm.git
cd pingcrmCreate the database:
createdb pingcrmOr via psql:
CREATE DATABASE pingcrm;Install and start Redis:
# macOS
brew install redis
brew services start redis
# Ubuntu/Debian
sudo apt install redis-server
sudo systemctl start redisVerify Redis is running:
redis-cli ping
# Should return: PONGcd backend
# Create virtual environment
python3.12 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Configure environment variables
cp .env.example .envEdit .env with your credentials (see Environment Variables for the full list):
# REQUIRED: Generate a secure secret key
SECRET_KEY=<run: python -c "import secrets; print(secrets.token_urlsafe(64))">
# Database
DATABASE_URL=postgresql+asyncpg://localhost:5432/pingcrm
# Redis
REDIS_URL=redis://localhost:6379/0Run database migrations:
alembic upgrade headcd frontend
npm installNo additional frontend configuration is needed for local development. The frontend proxies all /api/* requests to the backend via Next.js rewrites (default: http://localhost:8000, configurable via NEXT_PUBLIC_API_URL).
All platform integrations are optional. The app works without them -- you can add contacts manually or via CSV and connect platforms later.
- Go to Google Cloud Console
- Create a project (or select existing)
- Enable these APIs:
- Gmail API
- Google People API (for contacts)
- Google Calendar API
- Go to Credentials > Create Credentials > OAuth 2.0 Client ID
- Set application type to Web application
- Add authorized redirect URI:
http://localhost:3000/auth/google/callback - Copy Client ID and Client Secret to
.env:GOOGLE_CLIENT_ID=your_client_id GOOGLE_CLIENT_SECRET=your_client_secret
- Go to Twitter Developer Portal
- Create a project and app
- Enable OAuth 2.0 with PKCE
- Set callback URL:
http://localhost:3000/auth/twitter/callback - Request access to scopes:
dm.read,tweet.read,users.read,offline.access - Copy credentials to
.env:TWITTER_CLIENT_ID=your_client_id TWITTER_CLIENT_SECRET=your_client_secret TWITTER_API_KEY=your_api_key TWITTER_API_SECRET=your_api_secret TWITTER_REDIRECT_URI=http://localhost:3000/auth/twitter/callback
- Go to my.telegram.org
- Log in with your phone number
- Go to API development tools
- Create a new application
- Copy credentials to
.env:TELEGRAM_API_ID=your_api_id TELEGRAM_API_HASH=your_api_hash
- Go to Anthropic Console
- Create an API key
- Add to
.env:ANTHROPIC_API_KEY=your_api_key
You need 3-4 terminal windows for full functionality:
Terminal 1 -- Backend API:
cd backend
source .venv/bin/activate
uvicorn app.main:app --reload
# Runs on http://localhost:8000Terminal 2 -- Frontend:
cd frontend
npm run dev
# Runs on http://localhost:3000Terminal 3 -- Celery Worker + Beat (development, single process):
cd backend
source .venv/bin/activate
celery -A worker.celery_app worker --beat --loglevel=infoOr as separate processes (recommended for production):
# Terminal 3 -- Celery Beat (scheduler)
celery -A worker.celery_app beat --loglevel=info
# Terminal 4 -- Celery Worker
celery -A worker.celery_app worker --loglevel=infoOpen http://localhost:3000 in your browser.
# Set required env vars
export POSTGRES_PASSWORD=your_password
export SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(64))")
# Start all services
docker compose up
# Run migrations
docker compose exec backend alembic upgrade headFor production, use docker-compose.prod.yml which adds Caddy reverse proxy with automatic HTTPS.
| Variable | Required | Description |
|---|---|---|
SECRET_KEY |
Yes | JWT signing key. Generate with: python -c "import secrets; print(secrets.token_urlsafe(64))" |
DATABASE_URL |
Yes | PostgreSQL connection string (asyncpg format) |
REDIS_URL |
No | Redis URL for Celery (default: redis://localhost:6379/0) |
ALGORITHM |
No | JWT signing algorithm (default: HS256) |
ACCESS_TOKEN_EXPIRE_MINUTES |
No | JWT token lifetime in minutes (default: 1440, i.e. 24 hours) |
ENCRYPTION_KEY |
No | Fernet key for encrypting stored OAuth tokens. Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
CORS_ORIGINS |
No | JSON array of allowed CORS origins (default: ["http://localhost:3000","http://127.0.0.1:3000"]) |
AUTH_TOKEN |
No | auth_token cookie from x.com for Bird CLI |
CT0 |
No | ct0 CSRF cookie from x.com for Bird CLI |
CHROME_EXTENSION_ID |
No | Chrome extension ID for CORS (auto-detected in dev) |
GOOGLE_CLIENT_ID |
No | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
No | Google OAuth client secret |
GOOGLE_REDIRECT_URI |
No | Google OAuth callback URL (default: http://localhost:3000/auth/google/callback) |
TWITTER_API_KEY |
No | Twitter API v2 key |
TWITTER_API_SECRET |
No | Twitter API v2 secret |
TWITTER_CLIENT_ID |
No | Twitter OAuth 2.0 client ID |
TWITTER_CLIENT_SECRET |
No | Twitter OAuth 2.0 client secret |
TWITTER_REDIRECT_URI |
No | Twitter OAuth callback URL |
TWITTER_BEARER_TOKEN |
No | Twitter bearer token for app-only requests |
TELEGRAM_API_ID |
No | Telegram MTProto API ID (integer) |
TELEGRAM_API_HASH |
No | Telegram MTProto API hash |
ANTHROPIC_API_KEY |
No | Anthropic API key for Claude AI features |
NEXT_PUBLIC_API_URL |
No | Backend base URL used by the Next.js frontend (default: http://localhost:8000). Set this when deploying frontend and backend to different hosts. |
pingcrm/
├── README.md
├── CLAUDE.md # AI assistant instructions
├── mvp.md # Product specification
├── chrome-extension/ # LinkedIn companion Chrome extension (MV3)
├── docs/ # Docusaurus documentation site
│
├── backend/ # Python/FastAPI backend
│ ├── app/
│ │ ├── main.py # FastAPI app entry point + middleware
│ │ ├── api/ # Route handlers
│ │ │ ├── auth.py # Google OAuth + email/password auth
│ │ │ ├── contacts.py # Composition root — includes sub-routers
│ │ │ ├── contacts_routes/ # Contact route sub-modules
│ │ │ │ ├── crud.py # Create, read, update, delete
│ │ │ │ ├── listing.py # Paginated list + search
│ │ │ │ ├── taxonomy.py # Tags + stats
│ │ │ │ ├── imports.py # CSV + LinkedIn import
│ │ │ │ ├── sync.py # Google/Telegram/Twitter sync dispatch
│ │ │ │ ├── duplicates.py # Duplicate detection + merge
│ │ │ │ ├── messaging.py # Interaction timeline + message send
│ │ │ │ └── shared.py # Shared dependencies (router guards etc.)
│ │ │ ├── interactions.py # Interaction timeline endpoints
│ │ │ ├── suggestions.py # Follow-up suggestions
│ │ │ ├── telegram.py # Telegram auth + sync + common groups
│ │ │ ├── twitter.py # Twitter OAuth PKCE + sync
│ │ │ ├── organizations.py # Organization CRUD + merge
│ │ │ ├── identity.py # Identity resolution endpoints
│ │ │ ├── notifications.py # Notification management
│ │ │ └── linkedin.py # LinkedIn push endpoint + avatar download
│ │ ├── models/ # SQLAlchemy ORM models
│ │ │ ├── user.py
│ │ │ ├── contact.py
│ │ │ ├── contact_merge.py # Merge audit trail
│ │ │ ├── interaction.py
│ │ │ ├── detected_event.py
│ │ │ ├── follow_up.py # FollowUpSuggestion model
│ │ │ ├── identity_match.py
│ │ │ ├── organization.py
│ │ │ ├── notification.py
│ │ │ └── google_account.py
│ │ ├── schemas/ # Pydantic request/response schemas (typed Envelope[T])
│ │ ├── services/ # Business logic
│ │ │ ├── tasks.py # Re-export shim — backward-compatible Celery task names
│ │ │ ├── task_jobs/ # Celery task sub-modules by domain
│ │ │ │ ├── common.py # Shared notify helpers
│ │ │ │ ├── gmail.py # Gmail sync tasks
│ │ │ │ ├── telegram.py # Telegram sync tasks
│ │ │ │ ├── twitter.py # Twitter poll + DM sync tasks
│ │ │ │ ├── google.py # Google Contacts + Calendar tasks
│ │ │ │ ├── scoring.py # Relationship score tasks
│ │ │ │ ├── followups.py # Suggestion generation tasks
│ │ │ │ ├── maintenance.py # Snooze reactivation + org stats
│ │ │ │ └── tagging.py # Auto-tagging tasks
│ │ │ ├── followup_engine.py # Follow-up suggestion generation
│ │ │ ├── identity_resolution.py # Cross-platform matching
│ │ │ ├── message_composer.py # AI message drafting via Claude
│ │ │ ├── event_classifier.py # LLM-based event classification
│ │ │ ├── contact_search.py # Contact search/filter logic
│ │ │ ├── contact_import.py # CSV/LinkedIn import logic
│ │ │ ├── bio_refresh.py # Twitter bio refresh service
│ │ │ ├── telegram_service.py # Telegram orchestration
│ │ │ ├── digest_email.py # Weekly digest email
│ │ │ ├── scoring.py # Relationship score calculation
│ │ │ └── notifications.py # Notification creation helpers
│ │ ├── integrations/ # Third-party API clients
│ │ │ ├── gmail.py # Gmail thread sync
│ │ │ ├── google_auth.py # Google OAuth helpers
│ │ │ ├── google_calendar.py # Calendar event sync
│ │ │ ├── telegram.py # Telethon MTProto client
│ │ │ ├── twitter.py # Twitter API v2 client
│ │ │ ├── bird.py # Bird CLI (@steipete/bird) wrapper
│ │ │ └── linkedin.py # LinkedIn avatar download
│ │ └── core/ # Config, auth, database, encryption, Redis, Celery
│ ├── alembic/ # Database migrations
│ ├── tests/ # 631 pytest tests
│ ├── worker.py # Celery entry point
│ ├── requirements.txt
│ └── .env.example
│
└── frontend/ # Next.js 15 frontend
├── src/
│ ├── app/ # App Router pages
│ │ ├── dashboard/ # Main dashboard
│ │ ├── contacts/ # Contact list + new
│ │ │ └── [id]/ # Contact detail page
│ │ │ ├── _components/ # Detail UI components (timeline, panels, cards)
│ │ │ ├── _hooks/ # Controller hook (use-contact-detail-controller)
│ │ │ └── _lib/ # Helper utilities (formatters)
│ │ ├── organizations/ # Organization list + detail (inline editing)
│ │ ├── suggestions/ # Follow-up suggestions
│ │ ├── identity/ # Identity resolution UI
│ │ ├── notifications/ # Notification center
│ │ ├── settings/ # Platform connections + CSV import
│ │ │ ├── _components/ # Per-tab UI components (platform cards, import, tags)
│ │ │ └── _hooks/ # Controller hooks (settings, Telegram connect flow)
│ │ ├── onboarding/ # New user guided setup
│ │ ├── auth/ # Login, register, OAuth callbacks
│ │ ├── error.tsx # Error boundary
│ │ ├── global-error.tsx # Root error boundary
│ │ └── not-found.tsx # 404 page
│ ├── components/ # Reusable UI components
│ │ ├── timeline.tsx # Interaction timeline
│ │ ├── editable-field.tsx # Inline editing components
│ │ ├── score-badge.tsx # Relationship score badge
│ │ ├── csv-import.tsx # CSV drag-and-drop importer
│ │ ├── empty-state.tsx # Empty state placeholder
│ │ ├── message-editor.tsx # AI message editor
│ │ └── nav.tsx # Navigation bar with notification badge
│ ├── hooks/ # React Query data hooks
│ │ ├── use-auth.ts # Login, register, logout
│ │ ├── use-contacts.ts # Contact CRUD + search
│ │ ├── use-dashboard.ts # Dashboard stats
│ │ ├── use-identity.ts # Identity match operations
│ │ ├── use-notifications.ts # Notification queries
│ │ └── use-suggestions.ts # Follow-up suggestions
│ └── lib/ # Typed API client (openapi-fetch), utilities
├── vitest.config.ts
└── package.json
All endpoints return a standard envelope: { data, error, meta }.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/register |
Register with email/password |
| POST | /api/v1/auth/login |
Login with email/password |
| GET | /api/v1/auth/me |
Get current authenticated user profile |
| GET | /api/v1/auth/google/url |
Get Google OAuth authorization URL |
| POST | /api/v1/auth/google/callback |
Exchange Google OAuth code for JWT |
| GET | /api/v1/auth/google/accounts |
List connected Google accounts |
| DELETE | /api/v1/auth/google/accounts/{id} |
Remove a connected Google account |
| GET | /api/v1/auth/twitter/url |
Get Twitter OAuth 2.0 PKCE URL |
| POST | /api/v1/auth/twitter/callback |
Exchange Twitter OAuth code for JWT |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/contacts |
List contacts (paginated, searchable, sortable, filterable) |
| POST | /api/v1/contacts |
Create a contact |
| GET | /api/v1/contacts/tags |
List all unique tags |
| GET | /api/v1/contacts/stats |
Get contact statistics for dashboard |
| GET | /api/v1/contacts/{id} |
Get contact detail |
| PUT | /api/v1/contacts/{id} |
Update contact fields |
| DELETE | /api/v1/contacts/{id} |
Delete a contact |
| GET | /api/v1/contacts/{id}/duplicates |
Find potential duplicate contacts |
| POST | /api/v1/contacts/{id}/merge/{other_id} |
Merge two contacts into one |
| POST | /api/v1/contacts/{id}/refresh-bios |
Refresh Twitter/Telegram bios |
| POST | /api/v1/contacts/import/csv |
Import contacts from CSV file |
| POST | /api/v1/contacts/import/linkedin |
Import LinkedIn connections export |
| POST | /api/v1/contacts/import/linkedin-messages |
Import LinkedIn messages export |
| POST | /api/v1/contacts/scores/recalculate |
Recalculate all relationship scores |
All sync endpoints dispatch Celery tasks and return immediately with { "status": "started" }. A notification is created when the sync completes or fails.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/contacts/sync/google |
Sync Google Contacts (background) |
| POST | /api/v1/contacts/sync/google-calendar |
Sync Google Calendar events (background) |
| POST | /api/v1/contacts/sync/telegram |
Sync Telegram chats + groups + bios (background) |
| POST | /api/v1/contacts/sync/twitter |
Sync Twitter DMs + mentions + bios (background) |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/telegram/connect |
Send OTP to phone number |
| POST | /api/v1/auth/telegram/verify |
Verify OTP code |
| POST | /api/v1/auth/telegram/verify-2fa |
Complete 2FA password verification |
| POST | /api/v1/auth/telegram/sync |
Sync Telegram chats (background) |
| GET | /api/v1/contacts/{id}/telegram/common-groups |
Get shared Telegram groups with a contact |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/contacts/{id}/interactions |
Get interaction timeline for a contact |
| POST | /api/v1/contacts/{id}/interactions |
Add a manual interaction/note |
| PATCH | /api/v1/contacts/{id}/interactions/{iid} |
Update a manual note |
| DELETE | /api/v1/contacts/{id}/interactions/{iid} |
Delete a manual note |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/suggestions |
List follow-up suggestions |
| GET | /api/v1/suggestions/digest |
Get weekly digest suggestions |
| PUT | /api/v1/suggestions/{id} |
Update suggestion status (snooze/dismiss/send) |
| POST | /api/v1/suggestions/generate |
Generate new AI-powered suggestions |
| POST | /api/v1/suggestions/{id}/regenerate |
Regenerate AI message for a suggestion |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/identity/matches |
List pending identity matches |
| POST | /api/v1/identity/scan |
Trigger cross-platform identity scan |
| POST | /api/v1/identity/matches/{id}/merge |
Merge matched contacts |
| POST | /api/v1/identity/matches/{id}/reject |
Reject a false match |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/notifications |
List all notifications (paginated) |
| GET | /api/v1/notifications/unread-count |
Get unread notification count |
| PUT | /api/v1/notifications/{id}/read |
Mark a notification as read |
| PUT | /api/v1/notifications/read-all |
Mark all notifications as read |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/organizations |
List organizations (paginated, searchable) |
| POST | /api/v1/organizations/merge |
Merge multiple organizations into one |
| GET | /api/v1/organizations/{id} |
Get organization detail with contacts |
| PATCH | /api/v1/organizations/{id} |
Update organization fields |
| DELETE | /api/v1/organizations/{id} |
Delete organization (unlinks contacts) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
API health check |
| Task | Interval |
|---|---|
| Gmail sync (all users) | Every 6 hours |
| Google Calendar sync (all users) | Daily (06:00 UTC) |
| Telegram sync (all users) | Daily (03:00 UTC) -- chats only; groups/bios on-demand |
| Telegram bio recheck (non-2nd-tier) | Every 3 days (05:00 UTC) |
| Twitter activity + DM poll | Daily (04:00 UTC) |
| Relationship score recalculation | Daily (02:00 UTC) |
| Follow-up suggestion generation | Daily (08:00 UTC) |
| Weekly digest email | Weekly (Monday 09:00 UTC) |
| Snooze reactivation | Hourly |
| Organization stats refresh | Hourly |
# Backend tests (631 tests)
cd backend
pytest
# With coverage report
pytest --cov=app --cov-report=term-missing
# Frontend tests
cd frontend
npm test
# Frontend tests with watch mode
npm run test:watchThis project is licensed under the GNU Affero General Public License v3.0.
You are free to self-host, modify, and distribute PingCRM. If you run a modified version as a network service, you must make your source code available under the same license.