provider-endpointsProvider Overview

Provider Overview

This page explains how Aivida integrates external lab providers using a single, provider-agnostic architecture.

Why This Exists

  • Keep endpoint contracts stable even when providers change.
  • Add new providers with adapter registration only.
  • Enforce Aivida-first payment control before external booking.
  • Persist all critical linkage in Aivida tables for traceability.

High-Level Architecture

flowchart LR
  A["Aivida Client"] --> B["POST /api (namespace=labProvider)"]
  B --> C["Router Engine"]
  C --> D["LabProviderRegistry"]
  D --> E["Thyrocare Adapter (LabProviderClient)"]
  E --> F["Thyrocare APIs"]
  C --> G["Aivida DB (payments, lab_orders, provider_orders, lab_result_files)"]
  C --> H["Aivida FileStorage"]

Pay-Then-Book Flow

sequenceDiagram
  participant App as Aivida App
  participant API as Aivida API
  participant DB as Aivida DB
  participant Reg as Provider Registry
  participant T as Thyrocare

  App->>API: labProvider.createOrder(providerCode,paymentId,payload)
  API->>DB: GetPaymentByID(paymentId, organizationId)
  DB-->>API: payment row

  alt payment missing or status != success
    API-->>App: error (payment-first guard)
  else payment status = success
    API->>DB: check sourceType/sourceId linkage
    alt already linked
      API-->>App: existing providerOrderId/labOrderId (idempotent=true)
    else not linked
      API->>Reg: Resolve(providerCode)
      Reg-->>API: LabProviderClient
      API->>T: CreateOrder(payload)
      T-->>API: externalOrderId
      API->>DB: insert lab_orders
      API->>DB: insert provider_orders
      API->>DB: update payments.sourceType=provider_order
      API-->>App: providerOrderId, labOrderId, externalOrderId
    end
  end

Report Fetch Flow

flowchart TD
  A["labProvider.getReport"] --> B["Resolve provider via registry"]
  B --> C["Provider GetReport(externalOrderId, leadId)"]
  C --> D{"report URL present?"}
  D -- "No" --> E["Return provider error"]
  D -- "Yes" --> F["Download report bytes"]
  F --> G["Upload to Aivida FileStorage"]
  G --> H["Insert lab_result_files (is_external_result=true)"]
  H --> I["Return stable Aivida file URL + metadata"]

Data Ownership and Mapping

ConcernSource of Truth
Payment completionpayments
External booking referencelab_orders.order_id
Internal provider-order lifecycleprovider_orders
Report file metadatalab_result_files
External provider raw responseproviderRaw in endpoint response

Current Provider (v1)

  • Supported providerCode: thyrocare
  • Namespace: labProvider
  • Endpoints:
    • catalog
    • getPincodes
    • priceBreakup
    • searchSlots
    • createOrder
    • getOrder
    • listOrders
    • cancelOrder
    • rescheduleOrder
    • getReport

Operational Notes

  • v1 uses one platform Thyrocare account.
  • Provider operations like cancel/reschedule can be eventually consistent on provider side.
  • Status refresh is pull-based in v1 (getOrder, listOrders), not webhook-driven.
  • Adding a new provider requires implementing LabProviderClient and registering it in LabProviderRegistry.

Testing and Smoke Validation

cd backend
./scripts/thyrocare_smoke.sh
  • Full booking smoke (pay-then-book path):
cd backend
ORG_ID=org_test_thyro \
PAYMENT_ID=<payment_with_status_success> \
PATIENT_ID=<aivida_patient_id> \
./scripts/thyrocare_smoke.sh