Files
claudetools/.claude/SCHEMA_INTEGRATIONS.md
Mike Swanson 390b10b32c Complete Phase 6: MSP Work Tracking with Context Recall System
Implements production-ready MSP platform with cross-machine persistent memory for Claude.

API Implementation:
- 130 REST API endpoints across 21 entities
- JWT authentication on all endpoints
- AES-256-GCM encryption for credentials
- Automatic audit logging
- Complete OpenAPI documentation

Database:
- 43 tables in MariaDB (172.16.3.20:3306)
- 42 SQLAlchemy models with modern 2.0 syntax
- Full Alembic migration system
- 99.1% CRUD test pass rate

Context Recall System (Phase 6):
- Cross-machine persistent memory via database
- Automatic context injection via Claude Code hooks
- Automatic context saving after task completion
- 90-95% token reduction with compression utilities
- Relevance scoring with time decay
- Tag-based semantic search
- One-command setup script

Security Features:
- JWT tokens with Argon2 password hashing
- AES-256-GCM encryption for all sensitive data
- Comprehensive audit trail for credentials
- HMAC tamper detection
- Secure configuration management

Test Results:
- Phase 3: 38/38 CRUD tests passing (100%)
- Phase 4: 34/35 core API tests passing (97.1%)
- Phase 5: 62/62 extended API tests passing (100%)
- Phase 6: 10/10 compression tests passing (100%)
- Overall: 144/145 tests passing (99.3%)

Documentation:
- Comprehensive architecture guides
- Setup automation scripts
- API documentation at /api/docs
- Complete test reports
- Troubleshooting guides

Project Status: 95% Complete (Production-Ready)
Phase 7 (optional work context APIs) remains for future enhancement.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 06:00:26 -07:00

24 KiB

External Integrations Schema

MSP Mode Database Schema - External Systems Integration

Status: Designed 2026-01-15 (Future Capability) Database: msp_tracking (MariaDB on Jupiter)


Overview

The External Integrations subsystem enables MSP Mode to connect with external MSP platforms, automate workflows, and link session data to ticketing and documentation systems. This bridges MSP Mode's intelligent tracking with real-world business systems.

Core Integration Systems:

  • SyncroMSP - PSA/RMM platform (tickets, time tracking, assets)
  • MSP Backups - Backup management and reporting
  • Zapier - Automation platform (webhooks and triggers)

Related Documentation:


Tables Summary

Table Purpose Encryption
external_integrations Track all external system interactions No (API responses)
integration_credentials OAuth/API key storage for integrations AES-256-GCM
ticket_links Link sessions to external tickets No
backup_log Backup tracking with verification No

Total: 4 tables

Specialized Agent:

  • Integration Workflow Agent - Executes multi-step integration workflows (ticket updates, report pulling, file attachments)

Table Schemas

external_integrations

Comprehensive tracking of all interactions with external systems. Audit trail for integration workflows.

CREATE TABLE external_integrations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID REFERENCES sessions(id) ON DELETE CASCADE,
    work_item_id UUID REFERENCES work_items(id) ON DELETE CASCADE,
    client_id UUID REFERENCES clients(id) ON DELETE SET NULL,

    -- Integration details
    integration_type VARCHAR(100) NOT NULL CHECK(integration_type IN (
        'syncro_ticket', 'syncro_time', 'syncro_asset',
        'msp_backups_report', 'msp_backups_status',
        'zapier_webhook', 'zapier_trigger',
        'email_notification', 'custom_integration'
    )),
    integration_name VARCHAR(255), -- "SyncroMSP", "MSP Backups", "Zapier"

    -- External resource identification
    external_id VARCHAR(255), -- ticket ID, asset ID, webhook ID, etc.
    external_url VARCHAR(500), -- direct link to resource
    external_reference VARCHAR(255), -- human-readable: "T12345", "WH-ABC123"

    -- Action tracking
    action VARCHAR(50) CHECK(action IN (
        'created', 'updated', 'linked', 'attached',
        'retrieved', 'searched', 'deleted', 'triggered'
    )),
    direction VARCHAR(20) CHECK(direction IN ('outbound', 'inbound')),
    -- outbound: MSP Mode → External system
    -- inbound: External system → MSP Mode (via webhook)

    -- Request/Response data
    request_data TEXT, -- JSON: what we sent
    response_data TEXT, -- JSON: what we received
    response_status VARCHAR(50), -- "success", "error", "timeout"
    error_message TEXT,

    -- Performance tracking
    request_duration_ms INTEGER,
    retry_count INTEGER DEFAULT 0,

    -- Metadata
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(255), -- user who authorized

    INDEX idx_ext_int_session (session_id),
    INDEX idx_ext_int_work_item (work_item_id),
    INDEX idx_ext_int_client (client_id),
    INDEX idx_ext_int_type (integration_type),
    INDEX idx_ext_int_external (external_id),
    INDEX idx_ext_int_status (response_status),
    INDEX idx_ext_int_created (created_at)
);

Example Integration Records:

SyncroMSP Ticket Update:

{
  "session_id": "current-session-uuid",
  "client_id": "dataforth-uuid",
  "integration_type": "syncro_ticket",
  "integration_name": "SyncroMSP",
  "external_id": "12345",
  "external_url": "https://azcomputerguru.syncromsp.com/tickets/12345",
  "external_reference": "T12345",
  "action": "updated",
  "direction": "outbound",
  "request_data": {
    "comment": "Changes made today:\n- Configured Veeam backup job for D2TESTNAS\n- Set retention: 30 days local, 90 days cloud\n- Tested backup: successful (45GB)\n- Verified restore point creation",
    "internal": false
  },
  "response_data": {
    "comment_id": "67890",
    "created_at": "2026-01-15T14:32:10Z"
  },
  "response_status": "success",
  "request_duration_ms": 245,
  "created_by": "mike@azcomputerguru.com"
}

MSP Backups Report Retrieval:

{
  "session_id": "current-session-uuid",
  "client_id": "dataforth-uuid",
  "integration_type": "msp_backups_report",
  "integration_name": "MSP Backups",
  "action": "retrieved",
  "direction": "outbound",
  "request_data": {
    "customer": "Dataforth",
    "date": "2026-01-15",
    "format": "pdf"
  },
  "response_data": {
    "report_url": "https://storage.mspbackups.com/reports/dataforth_2026-01-15.pdf",
    "file_size_bytes": 1048576,
    "summary": {
      "total_jobs": 5,
      "successful": 5,
      "failed": 0,
      "total_size_gb": 245
    }
  },
  "response_status": "success",
  "request_duration_ms": 3420
}

SyncroMSP File Attachment:

{
  "session_id": "current-session-uuid",
  "integration_type": "syncro_ticket",
  "external_id": "12345",
  "action": "attached",
  "direction": "outbound",
  "request_data": {
    "file_name": "dataforth_backup_report_2026-01-15.pdf",
    "file_size_bytes": 1048576
  },
  "response_data": {
    "attachment_id": "att_789",
    "url": "https://azcomputerguru.syncromsp.com/attachments/att_789"
  },
  "response_status": "success"
}

Zapier Webhook Trigger (Inbound):

{
  "integration_type": "zapier_webhook",
  "external_id": "webhook_abc123",
  "action": "triggered",
  "direction": "inbound",
  "request_data": {
    "event": "ticket_created",
    "ticket_id": "12346",
    "customer": "Grabb & Durando",
    "subject": "Network connectivity issues"
  },
  "response_data": {
    "msp_mode_action": "created_pending_task",
    "task_id": "task-uuid"
  },
  "response_status": "success"
}

Failed Integration (Timeout):

{
  "integration_type": "syncro_ticket",
  "action": "updated",
  "direction": "outbound",
  "request_data": {
    "ticket_id": "12345",
    "comment": "Work completed..."
  },
  "response_status": "error",
  "error_message": "Request timeout after 30000ms",
  "request_duration_ms": 30000,
  "retry_count": 3
}

integration_credentials

Secure storage for integration authentication credentials (OAuth tokens, API keys).

CREATE TABLE integration_credentials (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    integration_name VARCHAR(100) NOT NULL UNIQUE, -- 'syncro', 'msp_backups', 'zapier'

    -- Credential type
    credential_type VARCHAR(50) CHECK(credential_type IN ('oauth', 'api_key', 'basic_auth', 'bearer_token')),

    -- Encrypted credentials (AES-256-GCM)
    api_key_encrypted BYTEA,
    oauth_token_encrypted BYTEA,
    oauth_refresh_token_encrypted BYTEA,
    oauth_client_id VARCHAR(255), -- not encrypted (public)
    oauth_client_secret_encrypted BYTEA,
    oauth_expires_at TIMESTAMP,
    basic_auth_username VARCHAR(255),
    basic_auth_password_encrypted BYTEA,

    -- OAuth metadata
    oauth_scopes TEXT, -- JSON array: ["tickets:read", "tickets:write"]
    oauth_authorize_url VARCHAR(500),
    oauth_token_url VARCHAR(500),

    -- API endpoints
    api_base_url VARCHAR(500) NOT NULL,
    webhook_url VARCHAR(500), -- for receiving webhooks
    webhook_secret_encrypted BYTEA,

    -- Status and health
    is_active BOOLEAN DEFAULT true,
    last_tested_at TIMESTAMP,
    last_test_status VARCHAR(50), -- "success", "auth_failed", "connection_error"
    last_test_error TEXT,
    last_used_at TIMESTAMP,

    -- Rate limiting
    rate_limit_requests INTEGER, -- requests per period
    rate_limit_period_seconds INTEGER, -- period in seconds
    rate_limit_remaining INTEGER, -- current remaining requests

    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_int_cred_name (integration_name),
    INDEX idx_int_cred_active (is_active)
);

Example Integration Credentials:

SyncroMSP (OAuth):

{
  "integration_name": "syncro",
  "credential_type": "oauth",
  "oauth_token_encrypted": "<encrypted_access_token>",
  "oauth_refresh_token_encrypted": "<encrypted_refresh_token>",
  "oauth_client_id": "syncro_client_id",
  "oauth_client_secret_encrypted": "<encrypted_secret>",
  "oauth_expires_at": "2026-01-16T14:30:00Z",
  "oauth_scopes": ["tickets:read", "tickets:write", "customers:read", "time_entries:write"],
  "oauth_authorize_url": "https://azcomputerguru.syncromsp.com/oauth/authorize",
  "oauth_token_url": "https://azcomputerguru.syncromsp.com/oauth/token",
  "api_base_url": "https://azcomputerguru.syncromsp.com/api/v1",
  "is_active": true,
  "last_tested_at": "2026-01-15T14:00:00Z",
  "last_test_status": "success",
  "rate_limit_requests": 1000,
  "rate_limit_period_seconds": 3600
}

MSP Backups (API Key):

{
  "integration_name": "msp_backups",
  "credential_type": "api_key",
  "api_key_encrypted": "<encrypted_api_key>",
  "api_base_url": "https://api.mspbackups.com/v2",
  "is_active": true,
  "last_tested_at": "2026-01-15T09:00:00Z",
  "last_test_status": "success"
}

Zapier (Webhook):

{
  "integration_name": "zapier",
  "credential_type": "bearer_token",
  "api_key_encrypted": "<encrypted_bearer_token>",
  "api_base_url": "https://hooks.zapier.com/hooks/catch",
  "webhook_url": "https://msp-api.azcomputerguru.com/api/v1/webhooks/zapier",
  "webhook_secret_encrypted": "<encrypted_webhook_secret>",
  "is_active": true
}

Security Features:

  • All sensitive fields encrypted with AES-256-GCM
  • Same master key as credentials table
  • Automatic OAuth token refresh
  • Rate limit tracking to prevent API abuse
  • Health check monitoring

Links MSP Mode sessions to external ticketing system tickets. Bi-directional reference.

CREATE TABLE ticket_links (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID REFERENCES sessions(id) ON DELETE CASCADE,
    client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
    work_item_id UUID REFERENCES work_items(id) ON DELETE SET NULL,

    -- Ticket identification
    integration_type VARCHAR(100) NOT NULL CHECK(integration_type IN (
        'syncro', 'autotask', 'connectwise', 'zendesk', 'freshdesk'
    )),
    ticket_id VARCHAR(255) NOT NULL, -- external system ticket ID
    ticket_number VARCHAR(100), -- human-readable: "T12345", "#12345"
    ticket_subject VARCHAR(500),
    ticket_url VARCHAR(500),
    ticket_status VARCHAR(100), -- "open", "in_progress", "resolved", "closed"
    ticket_priority VARCHAR(50), -- "low", "medium", "high", "critical"

    -- Linking metadata
    link_type VARCHAR(50) CHECK(link_type IN ('related', 'resolves', 'documents', 'caused_by')),
    -- related: session work related to ticket
    -- resolves: session work resolves the ticket
    -- documents: session documents work done for ticket
    -- caused_by: session work was triggered by ticket

    link_direction VARCHAR(20) CHECK(link_direction IN ('manual', 'automatic')),
    linked_by VARCHAR(255), -- user who created link

    -- Sync status
    auto_sync_enabled BOOLEAN DEFAULT false, -- auto-post session updates to ticket
    last_synced_at TIMESTAMP,
    sync_errors TEXT, -- JSON array of sync error messages

    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_ticket_session (session_id),
    INDEX idx_ticket_client (client_id),
    INDEX idx_ticket_work_item (work_item_id),
    INDEX idx_ticket_external (integration_type, ticket_id),
    INDEX idx_ticket_status (ticket_status)
);

Example Ticket Links:

Session Resolves Ticket:

{
  "session_id": "session-uuid",
  "client_id": "dataforth-uuid",
  "integration_type": "syncro",
  "ticket_id": "12345",
  "ticket_number": "T12345",
  "ticket_subject": "Backup configuration for NAS",
  "ticket_url": "https://azcomputerguru.syncromsp.com/tickets/12345",
  "ticket_status": "resolved",
  "ticket_priority": "high",
  "link_type": "resolves",
  "link_direction": "manual",
  "linked_by": "mike@azcomputerguru.com",
  "auto_sync_enabled": true,
  "last_synced_at": "2026-01-15T15:00:00Z"
}

Work Item Documents Ticket:

{
  "session_id": "session-uuid",
  "work_item_id": "work-item-uuid",
  "client_id": "grabb-uuid",
  "integration_type": "syncro",
  "ticket_id": "12346",
  "ticket_number": "T12346",
  "ticket_subject": "DNS migration to UDM",
  "link_type": "documents",
  "link_direction": "automatic"
}

Ticket Triggered Session:

{
  "session_id": "session-uuid",
  "client_id": "client-uuid",
  "integration_type": "syncro",
  "ticket_id": "12347",
  "ticket_subject": "Email delivery issues",
  "ticket_status": "in_progress",
  "link_type": "caused_by",
  "link_direction": "automatic",
  "auto_sync_enabled": true
}

backup_log

Backup tracking with verification status. Can be populated from MSP Backups integration or local backup operations.

CREATE TABLE backup_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_id UUID REFERENCES clients(id) ON DELETE SET NULL,
    infrastructure_id UUID REFERENCES infrastructure(id) ON DELETE SET NULL,
    session_id UUID REFERENCES sessions(id) ON DELETE SET NULL,

    -- Backup classification
    backup_type VARCHAR(50) NOT NULL CHECK(backup_type IN (
        'daily', 'weekly', 'monthly', 'manual', 'pre-migration',
        'pre-upgrade', 'disaster_recovery'
    )),
    backup_source VARCHAR(100), -- "local", "veeam", "msp_backups", "manual"

    -- File details
    file_path VARCHAR(500) NOT NULL,
    file_name VARCHAR(255),
    file_size_bytes BIGINT NOT NULL,
    storage_location VARCHAR(500), -- "NAS", "Cloud", "Local", "Off-site"

    -- Timing
    backup_started_at TIMESTAMP NOT NULL,
    backup_completed_at TIMESTAMP NOT NULL,
    duration_seconds INTEGER GENERATED ALWAYS AS (
        TIMESTAMPDIFF(SECOND, backup_started_at, backup_completed_at)
    ) STORED,

    -- Verification
    verification_status VARCHAR(50) CHECK(verification_status IN (
        'passed', 'failed', 'not_verified', 'in_progress'
    )),
    verification_method VARCHAR(100), -- "test_restore", "checksum", "file_count", "manual"
    verification_details TEXT, -- JSON: specific check results
    verification_completed_at TIMESTAMP,

    -- Backup metadata
    database_host VARCHAR(255),
    database_name VARCHAR(100),
    backup_method VARCHAR(50), -- "mysqldump", "mariabackup", "file_copy", "veeam"
    compression_type VARCHAR(50), -- "gzip", "zip", "none"
    encryption_enabled BOOLEAN DEFAULT false,

    -- Retention
    retention_days INTEGER,
    scheduled_deletion_date TIMESTAMP,
    deleted_at TIMESTAMP,

    -- Status
    backup_status VARCHAR(50) DEFAULT 'completed' CHECK(backup_status IN (
        'in_progress', 'completed', 'failed', 'deleted'
    )),
    error_message TEXT,

    -- Integration linkage
    external_integration_id UUID REFERENCES external_integrations(id),

    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_backup_client (client_id),
    INDEX idx_backup_infrastructure (infrastructure_id),
    INDEX idx_backup_type (backup_type),
    INDEX idx_backup_date (backup_completed_at),
    INDEX idx_backup_verification (verification_status),
    INDEX idx_backup_status (backup_status)
);

Example Backup Records:

Successful Daily Backup:

{
  "client_id": "dataforth-uuid",
  "infrastructure_id": "ad2-uuid",
  "backup_type": "daily",
  "backup_source": "veeam",
  "file_path": "/mnt/backups/AD2_2026-01-15_daily.vbk",
  "file_name": "AD2_2026-01-15_daily.vbk",
  "file_size_bytes": 48318382080,
  "storage_location": "D2TESTNAS",
  "backup_started_at": "2026-01-15T02:00:00Z",
  "backup_completed_at": "2026-01-15T02:45:30Z",
  "verification_status": "passed",
  "verification_method": "test_restore",
  "verification_details": {
    "restore_test_successful": true,
    "files_verified": 12543,
    "checksum_valid": true
  },
  "verification_completed_at": "2026-01-15T03:15:00Z",
  "backup_method": "veeam",
  "compression_type": "veeam_proprietary",
  "encryption_enabled": true,
  "retention_days": 30,
  "backup_status": "completed"
}

Pre-Migration Backup:

{
  "client_id": "grabb-uuid",
  "infrastructure_id": "pfsense-uuid",
  "session_id": "migration-session-uuid",
  "backup_type": "pre-migration",
  "backup_source": "manual",
  "file_path": "/backups/pfsense_config_pre_migration_2026-01-15.xml",
  "file_size_bytes": 524288,
  "storage_location": "Local",
  "backup_started_at": "2026-01-15T14:00:00Z",
  "backup_completed_at": "2026-01-15T14:00:15Z",
  "verification_status": "passed",
  "verification_method": "manual",
  "backup_method": "file_copy",
  "backup_status": "completed"
}

Failed Backup:

{
  "client_id": "client-uuid",
  "infrastructure_id": "nas-uuid",
  "backup_type": "daily",
  "backup_source": "veeam",
  "file_path": "/mnt/backups/NAS_2026-01-15_daily.vbk",
  "backup_started_at": "2026-01-15T02:00:00Z",
  "backup_completed_at": "2026-01-15T02:05:00Z",
  "backup_status": "failed",
  "error_message": "Insufficient disk space on target. Available: 2GB, Required: 50GB",
  "verification_status": "not_verified"
}

Database Backup:

{
  "backup_type": "daily",
  "backup_source": "local",
  "file_path": "/var/backups/mysql/msp_tracking_2026-01-15.sql.gz",
  "file_size_bytes": 10485760,
  "storage_location": "Jupiter",
  "backup_started_at": "2026-01-15T01:00:00Z",
  "backup_completed_at": "2026-01-15T01:02:30Z",
  "verification_status": "passed",
  "verification_method": "checksum",
  "database_host": "172.16.3.20",
  "database_name": "msp_tracking",
  "backup_method": "mysqldump",
  "compression_type": "gzip",
  "retention_days": 90,
  "backup_status": "completed"
}

Integration Workflows

SyncroMSP Ticket Update Workflow (Agent-Based)

User Request:

"Find the ticket for Dataforth about Backups - update it with the changes we've made today, and pull a report from MSP backups to attach to that ticket"

Execution:

  1. Main Claude launches Integration Workflow Agent

  2. Agent performs multi-step workflow:

    Step 1: Search for ticket

    GET https://azcomputerguru.syncromsp.com/api/v1/tickets?customer_id=12345&subject=backup
    Authorization: Bearer <oauth_token>
    
    • Result: Ticket #12345 "Backup configuration for NAS"

    Step 2: Generate work summary

    • Process current session work_items
    • Create dense summary:
      Changes made today:
      - Configured Veeam backup job for D2TESTNAS
      - Set retention: 30 days local, 90 days cloud
      - Tested backup: successful (45GB)
      - Verified restore point creation
      

    Step 3: Update ticket

    POST https://azcomputerguru.syncromsp.com/api/v1/tickets/12345/comments
    {
      "comment": "<work_summary>",
      "internal": false
    }
    
    • Store in external_integrations table

    Step 4: Pull backup report

    GET https://api.mspbackups.com/v2/reports?customer=Dataforth&date=2026-01-15
    
    • Receives report PDF (agent handles large file)
    • Summarize: "5 backup jobs, all successful, total size 245GB"

    Step 5: Attach report to ticket

    POST https://azcomputerguru.syncromsp.com/api/v1/tickets/12345/attachments
    Content-Type: multipart/form-data
    file: dataforth_backup_report.pdf
    

    Step 6: Create ticket link

    INSERT INTO ticket_links (
      session_id, client_id, integration_type,
      ticket_id, ticket_subject, link_type
    ) VALUES (
      'current-session-uuid', 'dataforth-uuid', 'syncro',
      '12345', 'Backup configuration for NAS', 'documents'
    );
    
  3. Agent returns concise summary:

    Workflow complete:
    ✓ Found ticket #12345: Backup configuration for NAS
    ✓ Added work summary comment
    ✓ Pulled backup report (5 jobs, all successful, 245GB)
    ✓ Attached report to ticket
    
  4. Main Claude confirms to user

Context Saved:

  • Agent handled all API calls, file transfers, database updates
  • Main Claude only received 50-word summary
  • Large PDF file never entered main context

Auto Time Tracking Workflow

When session ends with billable hours:

  1. Ask user:

    • "Log 2.5 hours to SyncroMSP ticket T12345? (y/n)"
  2. If yes, call SyncroMSP API:

    POST https://azcomputerguru.syncromsp.com/api/v1/time_entries
    {
      "ticket_id": 12345,
      "user_id": 12,
      "duration_minutes": 150,
      "work_description": "Backup configuration and testing",
      "billable": true
    }
    
  3. Log in external_integrations:

    {
      "integration_type": "syncro_time",
      "action": "created",
      "external_id": "time_entry_789",
      "request_data": {...},
      "response_status": "success"
    }
    

Backup Report Automation

Trigger: User mentions "backup" in MSP session

  1. Detect keyword "backup"

  2. Auto-suggest:

    • "Pull latest backup report for Dataforth? (y/n)"
  3. If yes, query MSP Backups API:

    GET https://api.mspbackups.com/v2/reports?customer=Dataforth&date=latest
    
  4. Display summary to user:

    • "Latest backup report: 5 jobs, all successful, 245GB total"
  5. Options:

    • Attach to ticket
    • Save to session
    • Email to client

OAuth Flow

User initiates: /msp integrate syncro

  1. Generate OAuth URL:

    https://azcomputerguru.syncromsp.com/oauth/authorize
      ?client_id=<client_id>
      &redirect_uri=https://msp-api.azcomputerguru.com/oauth/callback
      &response_type=code
      &scope=tickets:read tickets:write time_entries:write
    
  2. User authorizes in browser

  3. Callback receives authorization code:

    GET https://msp-api.azcomputerguru.com/oauth/callback?code=abc123
    
  4. Exchange code for tokens:

    POST https://azcomputerguru.syncromsp.com/oauth/token
    {
      "grant_type": "authorization_code",
      "code": "abc123",
      "client_id": "<client_id>",
      "client_secret": "<client_secret>",
      "redirect_uri": "https://msp-api.azcomputerguru.com/oauth/callback"
    }
    
  5. Encrypt and store tokens:

    INSERT INTO integration_credentials (
      integration_name, credential_type,
      oauth_token_encrypted, oauth_refresh_token_encrypted,
      oauth_expires_at, ...
    )
    
  6. Confirm to user:

    • "SyncroMSP connected successfully. Scopes: tickets:read, tickets:write, time_entries:write"

Security Considerations

API Key Storage

  • All integration credentials encrypted with AES-256-GCM
  • Same master key as credentials table
  • Separate from user credentials (different permission scopes)

OAuth Token Refresh

# Automatic token refresh before expiration
if oauth_expires_at <= NOW() + INTERVAL 5 MINUTE:
    # Refresh token
    response = requests.post(oauth_token_url, data={
        'grant_type': 'refresh_token',
        'refresh_token': decrypt(oauth_refresh_token_encrypted),
        'client_id': oauth_client_id,
        'client_secret': decrypt(oauth_client_secret_encrypted)
    })

    # Update stored tokens
    update_integration_credentials(
        new_access_token=response['access_token'],
        new_refresh_token=response.get('refresh_token'),
        expires_at=NOW() + response['expires_in']
    )

Rate Limiting

  • Track API rate limits per integration
  • Implement exponential backoff on rate limit errors
  • Queue requests if rate limit reached

Webhook Security

  • Verify webhook signatures
  • Store webhook secrets encrypted
  • IP whitelist for webhook endpoints (optional)

Future Enhancements

Phase 1 (MVP):

  • SyncroMSP ticket search and read
  • Manual ticket linking
  • Session summary → ticket comment (manual)

Phase 2:

  • MSP Backups report pulling
  • File attachments to tickets
  • OAuth token refresh automation
  • Auto-suggest ticket linking

Phase 3:

  • Zapier webhook triggers
  • Auto time tracking
  • Multi-step workflows
  • Natural language commands

Phase 4:

  • Bi-directional sync
  • Advanced automation
  • Additional PSA integrations (Autotask, ConnectWise)
  • IT Glue documentation sync

Document Version: 1.0 Last Updated: 2026-01-15 Author: MSP Mode Schema Design Team