ServicesCrelio AppArchitectureApp Modules

integration

External vendor integrations, webhooks, and third-party service connections

Integration App Architecture

Domain Responsibility

What This App Owns

  • Integration directory - Logging and retry for external calls
  • Vendor integrations - ABDM, QuickBooks, Tebra, Labcorp, etc.
  • Webhook management - Inbound/outbound webhook handling
  • Developer APIs - OAuth and API key management
  • Shipping integrations - Courier and logistics partners

What It Depends On

  • core/ - BaseModel, utilities, DocumentDB client
  • admin/ - Labs, settings
  • patient/ - Patient data for integrations
  • finance/ - Billing for claims
  • report/ - Reports for integrations

What Should NOT Be Added Here

  • Lab device parsing (belongs in interfacing/)
  • Payment processing (belongs in payments/)
  • Core notification logic (belongs in communication/)

Model-Centric Design (Fat Models)

Key Models

ModelResponsibilityKey FieldsStorage
IntegrationDirectoryIntegration log trackinglab_id, action, status, responseDocumentDB
IntegrationRetryInfoRetry configurationmax_retries, retry_count, last_retryDocumentDB
LabIntegrationLab-specific integration configintegration_type, credentials, is_activePostgreSQL
SupportedIntegrationAvailable integrations catalogname, type, configurationPostgreSQL
DeveloperAuthenticationAPI key managementapi_key, permissions, lab_idPostgreSQL

Business Logic in Models

IntegrationDirectory (integration/models/integration_directory.py) - 407 lines

Key Methods:

MethodPurpose
serialize_records()Serialize MongoDB/DocumentDB records
prepare_filters()Build aggregation filters
aggregate_log_summary()Summary statistics
get_valid_auto_retry_logs()Find retryable failures
update_retry_details_return_count()Update retry state
check_for_mirth_failure_auto_retry()MIRTH-specific retry logic
qualify_log_for_auto_retry()Determine if retry allowed
get_integration_summary()Dashboard summaries
fetch_integration_reports()Fetch logs with filters

Auto-Retry Error Messages:

auto_retry_error_messages = (
    "No response",
    "Connection Timeout",
    ...
)

Why Fat Model Style Here

Integration logging goes to DocumentDB but still uses model patterns:

  1. Consistent retry logic across all integrations
  2. Centralized error handling
  3. Audit trail for all external calls

Vendor Subdirectories

Each vendor has its own subdirectory with dedicated handlers:

VendorDirectoryPurpose
ABDMintegration/abdm/India Health Stack integration
QuickBooksintegration/quickbooks/Accounting integration
Tebraintegration/tebra/Practice management
Labcorpintegration/Labcorp/Reference lab
Hubspotintegration/Hubspot/CRM integration
Shippingintegration/shipping/Courier partners

ABDM Integration Structure

integration/abdm/
├── abdm_manager.py        # Main orchestrator
├── discovery_manager.py   # Patient discovery
├── healthid_handler.py    # HealthID operations
├── carecontext_handler.py # Care context linking
├── verify_patient_manager.py
├── proxies/               # Specialized proxies
├── views/                 # API endpoints
└── urls.py

Shipping Integration Structure

integration/shipping/
├── models/
│   └── shipping_services.py
├── serializers/
├── views/
└── (partner-specific handlers)

Data Access Patterns

DocumentDB Access

# integration/models/integration_directory.py
class IntegrationDirectory(DocumentDBModelBase):
    is_document_db_enabled = True
    document_db_table_name = "IntegrationDirectory"
    
    @classmethod
    def fetch_integration_reports(
        lab_id, lab_bill_ids=[], filters={}, limit=None
    ):
        """Query DocumentDB for integration logs"""
        collection = cls.get_collection()
        pipeline = cls.build_aggregation_pipeline(filters)
        return list(collection.aggregate(pipeline))

PostgreSQL + DocumentDB Pattern

Integration config in PostgreSQL, logs in DocumentDB:

# Check if integration is enabled
lab_integration = LabIntegration.objects.get(
    lab_id=lab_id, 
    integration_type="ABDM"
)

# Log to DocumentDB
IntegrationDirectory.create({
    "lab_id": lab_id,
    "action": "patient_discovery",
    "payload": request_data,
    "response": response_data,
    "status": "success"
})

API Layer (Wiring)

Endpoint Map

EndpointHandlerPurpose
/integration/logsIntegrationListViewList integration logs
/integration/retryIntegrationRetryViewManual retry
/integration/abdm/*abdm/views/ABDM endpoints
/integration/quickbooks/*quickbooks/views.pyQuickBooks OAuth + sync
/integration/webhookWebhookViewInbound webhooks

URL Routing

# integration/urls.py
urlpatterns = [
    path("logs/", IntegrationLogView.as_view()),
    path("abdm/", include("integration.abdm.urls")),
    path("quickbooks/", include("integration.quickbooks.urls")),
    path("shipping/", include("integration.shipping.urls")),
    # ... more vendor routes
]

Integrations (External)

Outbound Integration Flow

Retry Mechanism

# integration/utils.py
def send_request_to_retry(log_id, retry_id, lab_id, record):
    """Send failed request for retry via Fusion"""
    fusion_client = get_client("fusion")
    fusion_client.queue_job(
        "integration_retry",
        {
            "log_id": log_id,
            "retry_id": retry_id,
            "lab_id": lab_id,
            "record": record
        }
    )

X12 835 Processing (ERA)

# integration/utils.py
def parse_x12_and_build_payload(claim_response, lab_id, bill_id=None):
    """Parse X12 835 ERA and build claim payload"""
    raw_text = claim_response.x12_835_data
    segments = parse_x12(raw_text)
    parsed_data = parse_835(segments)
    
    # Build claim payload for QuickBooks
    return build_claim_payload(parsed_data, claim_mapping, lab_id)

Side Effects & Hidden Coupling

Logging Side Effects

Every integration call should:

  1. Create log entry before call
  2. Update log after response
  3. Queue for retry on failure

Cross-App Coupling

ImportUsed For
patient.models.user_detailsPatient data for HIS
finance.models.claimClaims for clearinghouse
report.models.lab_report_relationReports for HL7
admin.account.models.labsLab configuration

Performance & Scaling Notes

DocumentDB Considerations

  • Integration logs can grow large
  • Use aggregation pipelines for summaries
  • Archive old logs periodically

Async Processing

  • All external calls should go through Fusion
  • Retry with exponential backoff
  • Circuit breaker for failing endpoints

Hot Paths

PathConcernMitigation
Log creationHigh volumeBatch inserts
Retry pollingScheduled jobIndex on retry fields
Summary aggregationExpensiveCache results

Safe Extension Guide

Adding New Vendor Integration

  1. Create subdirectory: integration/{vendor}/
  2. Add files:
    integration/vendor/
    ├── __init__.py
    ├── client.py      # API client
    ├── manager.py     # Business logic
    ├── views.py       # Endpoints
    └── urls.py        # Routes
  3. Register in main urls.py
  4. Add to SupportedIntegration catalog

Adding New Integration Log Type

  1. Add to IntegrationDirectory log types
  2. Create summary aggregation if needed
  3. Add to dashboard queries

Patterns to Follow

  • Log all external calls to DocumentDB
  • Use retry mechanism for failures
  • Async via Fusion worker
  • OAuth tokens in encrypted storage

Patterns to Avoid

  • Synchronous external calls in request path
  • Storing credentials in plaintext
  • Skipping error logging

File Map

On this page