Implementation
Architecture, building blocks, logging decorators, outbound sequence, retry mechanics, and Mirth handoff for the Integration Dashboard backend.
Backend Implementation
The Integration Dashboard's backend decouples business triggers from transport and logging. Core workflows (billing, registration, sample lifecycle) complete without waiting for third-party responses. Logging is a passive side effect, not part of the execution path.
Logging is never in the critical path. If DocumentDB is unavailable or a transaction is broken, logging falls back to a Fusion webhook. The business action always completes regardless.
Architecture
Core Building Blocks
1. Event Vocabulary (actionCategory)
All integrations are keyed to a two-level event vocabulary:
actionCategory— broad business group (e.g., Billing, Sample Lifecycle, Registration).actionCategoryList— concrete triggerable event (e.g., "Bill Generation", "Sample Receive", "Report Signed").
All IntegrationDirectory log documents and labIntegration rows are keyed by actionCategoryListId. This is the primary join key across the dashboard.
2. Integration Root Record (developerAuthentication)
The master record for an integration account. It holds:
- Auth key and developer identity.
- Global enabled/disabled toggles.
- Lab/org ownership.
3. Delivery Configuration (labIntegration)
Maps an Action ID to a specific endpoint. Controls:
- Where to send the data — URL, or host/port for Mirth.
- How to send it — GET or POST, batch or single.
- Behavioral flags —
is_auto_retry,is_logs_disabled, specialized transport (Mirth via TCP, Fax via vendor).
4. Observability Layer (DocumentDB)
Operational logs live in DocumentDB because integration payloads are schema-variable and retry history needs append-only writes:
| Collection | Purpose |
|---|---|
IntegrationDirectory | Parent log per event — request body, headers, params, endpoint, status, response, response time, and business references (patient ID, bill ID, LRR ID, report ID) |
IntegrationRetryLog | One document per retry attempt, linked to parent via integration_directory_id |
Logging Decorators
Logging is implemented as passive decorator classes applied to specific functions. They observe the function they wrap, capture input/output, and persist a structured record. They do not route requests, queue tasks, or make any integration decisions.
Three coexisting implementations
All three logger implementations are active simultaneously and each serves a distinct scope:
IntegrationDirectoryLogger(livehealthapp / py2) — decorates inbound third-party API endpoints.WebhookIntegrationDirectoryLogger(livehealthapp / py2) — decorates internal webhook handlers (Mirth, fax, report email, outsource billing).IntegrationDirectoryLogger(crelio-app / py3) — a unified decorator covering inbound APIs, outbound webhooks, fax, and report endpoints triggered from the py3 service.
IntegrationDirectoryLogger
Applied to: Inbound API view functions — third-party systems calling LiveHealth APIs.
How it works:
- Extracts the
requestTokenfrom the incoming request to resolvelab_id,developer_id, and identity fields. - Calls the wrapped view function without any modification.
- After the function returns, assembles a log payload from:
- Request: body, headers, params, IP address, origin (mobile/web).
- Response: status code, body, response time.
- Business context: bill ID, patient ID, LRR ID (derived from the response if available).
- Saves the assembled payload to
IntegrationDirectoryviaDocumentDbClient.
Broken transaction handling: If the current DB transaction has needs_rollback=True (inside an atomic() block poisoned by an exception), the decorator cannot write to DocumentDB directly. It falls back to a Fusion webhook pointing to an internal log-creation endpoint, ensuring the record is persisted once the atomic block exits.
Short-circuit conditions (decorator skips logging entirely and just runs the function):
DOCUMENT_DB_ENABLEDisFalse.- Request body cannot be parsed.
is_api_retryflag is set in the body (retry calls skip re-logging).- No valid
requestTokenfound for the auth key.
@csrf_exempt
@IntegrationDirectoryLogger()
def appointmentConfirmAPI(request, authKey):
...WebhookIntegrationDirectoryLogger
Applied to: Internal webhook handler functions that perform the actual outbound call to a third-party system — Mirth handoff, fax delivery, report email, outsource billing.
These handlers are invoked by Fusion workers. The incoming request body always carries an integration_payload dict, built earlier by get_integration_payload() and passed through the Fusion task.
How it works:
- Reads
integration_payloadfrom the request body. - Calls the wrapped handler function without any modification.
- After the handler returns, inspects the response to determine outcome.
| Mode | Condition | Action |
|---|---|---|
| Update | is_outbound_webhook_endpoint=True | Updates the existing IntegrationDirectory doc by log_id (pre-created by save_log_instance) |
| Create | is_outbound_webhook_endpoint=False | Saves a new IntegrationDirectory doc after the handler completes (used for fax, report email) |
| Retry | is_retry_enabled=True | Delegates to IntegrationRetryLog.update_existing_record_and_push_update() instead of creating a new log |
Status resolution:
SUCCESS— HTTP 2xx and (where applicable)sent_to_mirth=True.FAIL— Non-2xx or explicit error body.QUEUED— Special case for async fax vendors (e.g., HumbleFax) where delivery is deferred.""(blank) — Response code209or suppression tag in body — used to suppress noisy/expected errors from the dashboard view.
# Outbound handler — updates the pre-created log
@WebhookIntegrationDirectoryLogger(is_outbound_webhook_endpoint=True)
def send_data_to_mirth(request):
...
# Fax/report handler — creates a new log after completion
@WebhookIntegrationDirectoryLogger(is_retry_enabled=True)
def send_report_email_webhook(request):
...IntegrationDirectoryLogger (crelio-app / py3)
Repository: crelio-app (Python 3)
A unified decorator that consolidates the responsibilities of both py2 decorators into a single class. It is the primary logger for integrations triggered from the py3 service. Currently active for Action IDs 60 (Claim Submission Webhook) and 61 (Claim Approval / Remittance Webhook), and is intended to become the standard for all new integrations built in crelio-app.
Modes — controlled by constructor flags:
| Flag | Mode | Applied To |
|---|---|---|
(no flags) — is_internal_api=True | Inbound API | Third-party systems calling a crelio-app endpoint with a RequestToken |
is_third_party_endpoint=True | Third-party API | Endpoints with no integration_payload in the body; payload is built from request metadata |
is_outbound_webhook_endpoint=True | Outbound Webhook | Internal handlers dispatched by Fusion; updates a pre-created log by log_id |
is_retry_enabled=True | Retry | Delegates outcome to IntegrationRetryLog.update_existing_record_and_push_update() |
How it works:
- Extracts the
HttpRequestor DRFRequestobject from function arguments. - Depending on the mode, builds the
integration_payload, resolveslab_id, and (for outbound) readslog_idfrom the request body. - Calls the wrapped function without any modification.
- After the function returns (or raises), parses the response to determine
status,error_message,response_time, andsent_to_mirth. - Persists the assembled log:
- Outbound mode: updates the existing
IntegrationDirectorydoc bylog_id. - Retry mode: delegates to
IntegrationRetryLog.update_existing_record_and_push_update(). - All other modes: saves a new
IntegrationDirectorydocument.
- Outbound mode: updates the existing
Broken transaction handling: Same pattern as py2 — if connection.needs_rollback=True inside an atomic() block, the decorator falls back to a Fusion webhook (/api-v3/integration/logs/new or /api-v3/integration/logs/update) to persist the record out-of-band.
Short-circuit conditions (decorator skips logging and just runs the function):
integration_payloadorlab_idcannot be resolved.- Outbound mode:
log_idis missing. - Third-party mode: always proceeds (no short-circuit — payload is built from metadata).
Status resolution:
SUCCESS— HTTP 2xx (andsent_to_mirth=Truefor Mirth outbound).FAIL— Non-2xx or explicit error body.QUEUED— HumbleFax vendor (fax delivery is async).""(blank) — Response code209or#NOTFORDASHBOARDin error message — suppresses record from dashboard view.
# Inbound API endpoint (default mode)
@IntegrationDirectoryLogger()
def get(self, request):
...
# Outbound webhook handler (updates pre-created log)
@IntegrationDirectoryLogger(is_outbound_webhook_endpoint=True)
def post(self, request):
...
# Retry-enabled handler
@IntegrationDirectoryLogger(is_retry_enabled=True)
def post(self, request):
...triggered_by_py3 flag
Logs originating from crelio-app set triggered_by_py3=True on the IntegrationDirectory document. The auto-retry scheduler uses this flag to route retry calls to the py3 retry endpoint (/api-v3/integration/retry-integration/...) instead of the py2 endpoint.
get_integration_payload()
Location: crm/integrations/utils.py
This is the standard payload builder called by trigger functions before queuing a Fusion task. It is a regular function returning a dict, not a decorator.
What it builds:
- Business context:
lab_id,lab_bill_id,patient_id,lrr_id,report_id,test_names. - Integration metadata:
action_category_id,action_category_list_id,developer_id,webhook_id. - Dispatch config:
request_type,is_batch,end_point,extra_data. - Retry context: serialized
retry_contextfor future intent reconstruction.
Gatekeeping — returns {} and skips logging if:
labIntegration.is_logs_disabledisTrue.labIntegration.urlis empty.- The endpoint URL resolves to a path in
INBOUND_API_PATH_LIST(prevents self-referential logging loops).
The returned payload is passed to save_log_instance() to pre-create a QUEUED-equivalent log before Fusion dispatch. The resulting log_id (the DocumentDB _id) is injected back into the payload so that WebhookIntegrationDirectoryLogger can locate and update the correct record when the handler completes.
Outbound Push — Step by Step
The trigger function does not make the HTTP call itself. It queues a Fusion task, and the Fusion worker (webhooks.py) handles the actual dispatch. Status is reported back via integration_callback_url.
Example: Billing API Trigger Flow
To understand how a particular endpoint triggers an integration and captures a log, consider the Bill Generation flow:
- Endpoint Triggered: The client hits the billing API, routed via
url(r'^billing/$', BillingView.as_view()). - Business Logic: The
BillingViewclass processes thePOSTrequest and delegates to thebill_patient()core utility function to create the bill. - Trigger Evaluation: Once the bill is saved and finalized,
bill_patient()callscommomFunctionForIntegrationBillCategory(). This function evaluates active integrations for the Bill Generation action category. - Payload Construction: Inside the trigger function,
get_integration_payload()is executed to prepare the exact integration payload. - Log Capture: During payload construction, a log document is pre-created in DocumentDB (with a
QUEUEDstatus). The generatedlog_idand theintegration_callback_urlare embedded into the payload. - Task Dispatch:
commonFunctionForIntegrationWebhookCall()is then called, which passes the payload to Fusion. - Callback Execution: The Fusion worker makes the outbound HTTP call to the third party. Upon completion, it POSTs the result back to the
integration_callback_url, where@WebhookIntegrationDirectoryLoggerupdates the previously captured log withSUCCESSorFAIL.
Key points:
integration_callback_urlis baked intointegration_payloadbyget_integration_payload()at trigger time. The Fusion worker doesn't need to know anything about the dashboard — it just POSTs to this URL after every call.- The suppression check (code
209/#NOTFORDASHBOARD) happens inside the Fusion worker, before the callback fires. Suppressed responses never reachWebhookIntegrationDirectoryLogger. - The
x-internal-tokenheader on the callback POST identifies it as an internal system call.
Retry Mechanism
Failed integrations can be retried manually from the dashboard or automatically based on labIntegration config.
Manual Retry
Initiated via the dashboard UI, routed through RetryIntegrationView.
- Fetches the parent
IntegrationDirectorydocument bylog_id. - Reads
action_category_list_idto look up the corresponding trigger function viaACTION_CATEGORY_TO_META. - Reads
retry_contextfrom the original log to reconstruct the business arguments. - Calls the appropriate
_prepare_kwargs_*function to rebuild fresh domain objects. - Calls the original trigger function with the rebuilt arguments.
WebhookIntegrationDirectoryLogger(withis_retry_enabled=True) captures the retry outcome and callsIntegrationRetryLog.update_existing_record_and_push_update().- The parent
IntegrationDirectorydocument'sretry_countis incremented andstatusupdated. - A Pusher notification is dispatched via
UpdateRetryIntegrationStatusto update the dashboard in real time.
Auto-Retry
Controlled per labIntegration row:
is_auto_retry— enables the feature for that action.auto_retry_attempts— maximum automatic attempts before giving up.
Auto-retry scans for FAIL or QUEUED logs that qualify and schedules them asynchronously. It uses the same intent-reconstruction pipeline as manual retry.
Intent Reconstruction (_prepare_kwargs_*)
Retries do not replay the original serialized request body. The system maps the log back to its triggering function and rebuilds domain objects from the database, ensuring any state changes since the first failure (e.g., updated patient record, corrected bill) are included.
- Each retriable action maps to a
_prepare_kwargs_*function incrm/integrations/utils.py. - These functions read
retry_context(saved in the original log) and use it to re-fetch live ORM objects. - The rebuilt kwargs are passed directly to the original trigger function.
| Function | What it rebuilds |
|---|---|
_prepare_kwargs_commomFunctionForIntegrationBillCategory | Fetches fresh billing object and re-serializes all LRRs |
_prepare_kwargs_common_integration_sample_receive | Re-fetches labReportRelation queryset by report IDs stored in context |
_prepare_kwargs_webhook_for_patient_registration | Rebuilds patient ID, org ID, referral, and merge flags from context |
_prepare_kwargs_AppointmentBookingCreationWebhook | Re-fetches emrAppointments by ID |
_prepare_kwargs_homeCollectionBookingWebhook | Re-fetches homeCollection by ID |
Mirth / HL7 Handoff
For Mirth integrations, the transport is TCP socket (not HTTP). The trigger function calls send_hl7_manual_sample_update() or equivalent, which:
- Reads host, port, and transport settings from
labIntegration.integrationExtraDetails. - Calls
update_message_with_ids()to injectLABIDandLOGIDinto the HL7 message body for downstream traceability, and stamps the log document withstage="LIVEHEALTHAPI". - Opens a TCP socket and sends the formatted HL7 message to Mirth.
WebhookIntegrationDirectoryLoggerwraps the handler and records the outcome.
Mirth handoffs often remain in QUEUED until downstream socket confirmation is received. This is expected behavior — the handoff succeeded, but Mirth's processing pipeline has not yet confirmed delivery.
Debugging Mental Model
When investigating or extending an integration, trace these four steps:
- Identify the event — What business action fired? (e.g., bill generated, sample received).
- Check configuration — Does the lab have an active
labIntegrationrow for thatactionCategoryListId? - Trace the trigger — Which function in
integration_functions.pycallsget_integration_payload()and queues the Fusion task? - Read the log — Find the
IntegrationDirectorydocument. Checkstatus,error_message,response_body, andretry_count.
Finding the log_id
The log_id (DocumentDB _id) is the single thread that connects the pre-created log, the Fusion payload, the handler execution, and the retry record. If something went wrong, find the log_id first.
Backend
Backend engineering documentation for the Integration Dashboard — trigger functions, logging decorators, Fusion queueing, DocumentDB observability, Mirth handoff, and retry mechanics.
Action Inventory
Canonical list of all supported integration Action IDs, grouped by business category with trigger family mappings.