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 clientadmin/- Labs, settingspatient/- Patient data for integrationsfinance/- Billing for claimsreport/- 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
| Model | Responsibility | Key Fields | Storage |
|---|---|---|---|
IntegrationDirectory | Integration log tracking | lab_id, action, status, response | DocumentDB |
IntegrationRetryInfo | Retry configuration | max_retries, retry_count, last_retry | DocumentDB |
LabIntegration | Lab-specific integration config | integration_type, credentials, is_active | PostgreSQL |
SupportedIntegration | Available integrations catalog | name, type, configuration | PostgreSQL |
DeveloperAuthentication | API key management | api_key, permissions, lab_id | PostgreSQL |
Business Logic in Models
IntegrationDirectory (integration/models/integration_directory.py) - 407 lines
Key Methods:
| Method | Purpose |
|---|---|
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:
- Consistent retry logic across all integrations
- Centralized error handling
- Audit trail for all external calls
Vendor Subdirectories
Each vendor has its own subdirectory with dedicated handlers:
| Vendor | Directory | Purpose |
|---|---|---|
| ABDM | integration/abdm/ | India Health Stack integration |
| QuickBooks | integration/quickbooks/ | Accounting integration |
| Tebra | integration/tebra/ | Practice management |
| Labcorp | integration/Labcorp/ | Reference lab |
| Hubspot | integration/Hubspot/ | CRM integration |
| Shipping | integration/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.pyShipping 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
| Endpoint | Handler | Purpose |
|---|---|---|
/integration/logs | IntegrationListView | List integration logs |
/integration/retry | IntegrationRetryView | Manual retry |
/integration/abdm/* | abdm/views/ | ABDM endpoints |
/integration/quickbooks/* | quickbooks/views.py | QuickBooks OAuth + sync |
/integration/webhook | WebhookView | Inbound 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:
- Create log entry before call
- Update log after response
- Queue for retry on failure
Cross-App Coupling
| Import | Used For |
|---|---|
patient.models.user_details | Patient data for HIS |
finance.models.claim | Claims for clearinghouse |
report.models.lab_report_relation | Reports for HL7 |
admin.account.models.labs | Lab 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
| Path | Concern | Mitigation |
|---|---|---|
| Log creation | High volume | Batch inserts |
| Retry polling | Scheduled job | Index on retry fields |
| Summary aggregation | Expensive | Cache results |
Safe Extension Guide
Adding New Vendor Integration
- Create subdirectory:
integration/{vendor}/ - Add files:
integration/vendor/ ├── __init__.py ├── client.py # API client ├── manager.py # Business logic ├── views.py # Endpoints └── urls.py # Routes - Register in main
urls.py - Add to
SupportedIntegrationcatalog
Adding New Integration Log Type
- Add to
IntegrationDirectorylog types - Create summary aggregation if needed
- 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
| File | Purpose |
|---|---|
| integration/models/init.py | Model exports |
| integration/models/integration_directory.py | Log tracking (407 lines) |
| integration/models/integration_retry_info.py | Retry config |
| integration/models/lab_integration.py | Lab config |
| integration/utils.py | Utilities (790 lines) |
| integration/abdm/ | ABDM integration (19 files) |
| integration/quickbooks/ | QuickBooks (4 files) |
| integration/shipping/ | Shipping (35 files) |
| integration/tebra/ | Tebra |
| integration/Labcorp/ | LabCorp |
| integration/views/ | API views |
| integration/urls.py | URL routing |