Skip to content

External Integrations Catalog

A single, source-cited catalog of every third-party (and cross-service) integration the mr-mentor-backend API talks to: what it does, the service/controller that wraps it, the env vars it reads, whether traffic is outbound (the API calls them) or inbound (they call the API via webhook), how it authenticates, and what happens when it is unconfigured or fails. Use this as the index page for integration work; each row links to the feature doc that owns the business logic.

Status: documented from source on this branch.


Overview

The backend is the single integration hub for the whole MAS suite. Frontends never call third-party APIs directly with secrets — they call this Express API, which holds the credentials and proxies to the outside world. Integrations fall into six categories:

Category Systems
Payments Razorpay
Comms Exotel (calls/SMS), WhatsApp (Meta Cloud / AiSensy), Nodemailer/Gmail SMTP
AI ElevenLabs + Aarya (batch AI calling), MissOzone via LiveKit (AI voice agent), LLM Gateway (LiteLLM), Groq (Ask MAS)
Calendar / Storage Google OAuth + Calendar + Meet + Drive, AWS S3, Redis
LMS / Exam Graphy / Mr.Learn (mrlearn.in), Mr.Test / EzExam, Judge0 (code execution)
Signing Leegality (e-sign)

Two recurring wiring patterns appear throughout:

  • Outbound proxy — a service holds the API key (from env or from an encrypted DB row) and calls the vendor. Most integrations are this.
  • Inbound webhook — the vendor posts back to a public (unauthenticated-by-JWT) route guarded by a shared secret in the query/header. Exotel, WhatsApp, and MissOzone/LiveKit use this.

Almost every wrapper is fail-soft: if its credentials are absent it reports "not configured" and the owning feature degrades gracefully (e.g. CRM falls back to tel: links, Ask MAS returns HTTP 503, email logs a warning and no-ops) rather than crashing the server.

Personas touched: students/users (payments, AI assistant, code runner), mentors (calendar, payouts), admins/HR (AI calling, WhatsApp, LMS sync), sales (telephony, WhatsApp), superadmin (Razorpay reporting, finance), and the platform itself (S3, Redis, email queue).


Key concepts & entities

  • Wrapper service — the src/services/*Service.ts (or controller) that owns one vendor's transport, auth, and error handling. Nothing else in the codebase should new-up a vendor SDK or fetch a vendor URL directly.
  • isConfigured() — a common method on a wrapper that returns whether the required env vars are present; callers branch on it to enable/disable a feature.
  • DB-stored credentials — several integrations keep per-tenant or per-user secrets in Postgres, AES-256-GCM encrypted, instead of (or layered over) env: mrlearn.auth_credentials, WhatsAppConfig, UserLlmKey, and the system-config table.
  • Shared-secret webhook — a public route that authenticates the vendor (not a user) by comparing a token/secret it posts against an env value.

Integration-adjacent TypeORM entities (config + audit, not the vendor's own data):

Entity File Holds
GoogleAuthTokens src/entities/GoogleAuthTokens.ts Per-user Google OAuth access/refresh tokens
WhatsAppConfig src/entities/WhatsAppConfig.entity.ts Per-user WhatsApp provider creds (encrypted)
WhatsAppMessage src/entities/WhatsAppMessage.entity.ts Outbound/inbound WhatsApp message log
LeadWhatsAppLog src/entities/LeadWhatsAppLog.ts CRM lead WhatsApp send log
ApplicationWhatsAppMessage src/entities/ApplicationWhatsAppMessage.entity.ts Candidate WhatsApp messages
AaryaCallBatch src/entities/AaryaCallBatch.ts ElevenLabs batch-call jobs + sync state
MissOzoneCall src/entities/MissOzoneCall.entity.ts LiveKit AI voice-agent call records
VoiceInterview src/entities/VoiceInterview.entity.ts Mr.Hire voice interview (synced from mr-hire-backend)
UserLlmKey src/entities/UserLlmKey.ts Per-user LiteLLM virtual key (encrypted)
AgentConfiguration src/entities/AgentConfiguration.ts LLM agent config consumed by the gateway
MrLearnAuthCredentials src/entities/mrlearn/MrLearnAuthCredentials.ts Graphy session creds (encrypted)
MrLearnSyncConfig src/entities/mrlearn/MrLearnSyncConfig.ts Per-Graphy-course sync config
MrTestSyncConfig src/entities/mrtest/MrTestSyncConfig.ts Per-exam EzExam sync config

Architecture

API wrappers grouped by category, mapped to their external systems.

flowchart LR
    subgraph API["mr-mentor-backend (Express)"]
        direction TB
        TKN["TokenService / RazorpayAdminService"]
        EXO["ExotelService"]
        WA["WhatsAppService"]
        MAIL["EmailService via emailQueue"]
        EL["ElevenLabsBatchService / AaryaCallSyncService"]
        OZ["MissOzoneService"]
        LLM["LlmGatewayService"]
        GROQ["AskMasService"]
        GCAL["GoogleCalendarService / GoogleAuthService"]
        GDRIVE["GoogleDriveConnectorService"]
        S3W["S3Service / s3Uploader"]
        REDIS["redis config + BullMQ"]
        GRAPHY["GraphyLmsService / MrLearnSyncService"]
        EZ["EzExamService / MrTestSyncService"]
        J0["Judge0Controller"]
        LEE["LeegalitySandboxService"]
    end

    subgraph PAY["Payments"]
        RZP["Razorpay API"]
    end
    subgraph COMMS["Comms"]
        EXOAPI["Exotel REST (calls/SMS)"]
        META["Meta Cloud / AiSensy"]
        SMTP["Gmail SMTP"]
    end
    subgraph AI["AI"]
        ELAPI["ElevenLabs Conversational AI"]
        LK["LiveKit voice agent (mas-voice-agent)"]
        LITE["LiteLLM gateway (mas-llm-gateway)"]
        GROQAPI["Groq API"]
    end
    subgraph CALSTORE["Calendar / Storage"]
        GOOG["Google OAuth / Calendar / Meet / Drive"]
        AWS["AWS S3 + CloudFront"]
        RDS["Redis"]
    end
    subgraph LMS["LMS / Exam"]
        GR["Graphy / Mr.Learn (mrlearn.in)"]
        EXAM["Mr.Test / EzExam"]
        JUDGE["Judge0 (self-hosted)"]
    end
    subgraph SIGN["Signing"]
        LEEAPI["Leegality eSign"]
    end

    TKN --> RZP
    EXO --> EXOAPI
    WA --> META
    MAIL --> SMTP
    EL --> ELAPI
    OZ --> LK
    LLM --> LITE
    GROQ --> GROQAPI
    GCAL --> GOOG
    GDRIVE --> GOOG
    S3W --> AWS
    REDIS --> RDS
    GRAPHY --> GR
    EZ --> EXAM
    J0 --> JUDGE
    LEE --> LEEAPI

    EXOAPI -. "POST /api/exotel/call-status" .-> EXO
    META -. "POST /api/whatsapp/webhook" .-> WA
    LK -. "POST /api/miss-ozone/livekit-webhook" .-> OZ
    GOOG -. "OAuth callback" .-> GCAL

Data model

Integration-config and audit entities owned by this repo (the vendor's own records live vendor-side).

erDiagram
    USER ||--o| GOOGLEAUTHTOKENS : "has"
    USER ||--o| WHATSAPPCONFIG : "has"
    USER ||--o| USERLLMKEY : "has"
    WHATSAPPCONFIG ||--o{ WHATSAPPMESSAGE : "logs"
    AARYACALLBATCH ||--o{ MISSOZONECALL : "unrelated"
    MRLEARNSYNCCONFIG ||--o{ MRLEARNAUTHCREDENTIALS : "uses"

    USER {
        string id PK
        string email
        string role
    }
    GOOGLEAUTHTOKENS {
        string id PK
        string userId FK
        string accessToken
        string refreshToken
        string scope
    }
    WHATSAPPCONFIG {
        string id PK
        string userId FK
        string provider
        string accessTokenEncrypted
        string status
    }
    WHATSAPPMESSAGE {
        string id PK
        string direction
        string status
        string waMessageId
    }
    USERLLMKEY {
        string id PK
        string userId FK
        string litellmKeyEncrypted
    }
    AARYACALLBATCH {
        string id PK
        string elevenlabsBatchId
        string status
    }
    MISSOZONECALL {
        string id PK
        string roomName
        string status
    }
    MRLEARNSYNCCONFIG {
        string id PK
        string graphyCourseId UK
    }
    MRLEARNAUTHCREDENTIALS {
        string id PK
        string cookieEncrypted
    }

Note: WHATSAPPCONFIG.providermeta_cloud | aisensy; WHATSAPPMESSAGE.directionoutbound | inbound. AaryaCallBatch and MissOzoneCall are independent (shown adjacent only for layout).


API surface

Integration-facing routes (the ones an external system or an integration UI hits). Prefixes are from src/routes/index.ts.

Method Path Auth/role Purpose
POST /api/exotel/call-status Public + EXOTEL_WEBHOOK_TOKEN query token Exotel call-status callback (ExotelWebhookRoutes)
GET /api/whatsapp/webhook Public + verify token Meta Cloud webhook verification handshake
POST /api/whatsapp/webhook Public Meta Cloud inbound message + status callbacks
POST /api/hr/whatsapp/send authMiddleware HR/sales sends a WhatsApp message
GET /api/admin/whatsapp/configs authMiddleware (admin) Manage per-user WhatsApp provider configs
POST /api/miss-ozone/livekit-webhook Public + header secret LiveKit room/agent event callback
GET /api/miss-ozone/me/calls authMiddleware Student lists own AI voice-agent calls
GET /api/admin/aarya/config authMiddleware (admin) ElevenLabs/Aarya batch-calling config
POST /api/admin/aarya/batches authMiddleware (admin) Submit a batch call job to ElevenLabs
GET /api/admin/aarya/conversations/:id/audio authMiddleware (admin) Proxy ElevenLabs call recording
GET /api/google-calendar/... authMiddleware Calendar connect/sync (mentor meetings)
GET /api/google-drive-connector/callback OAuth redirect Google Drive OAuth callback
POST /api/judge0/submissions Public Create Judge0 code submission
GET /api/judge0/submissions/:token Public Fetch Judge0 result
POST /api/judge0/run-tests Public Run code against test cases
GET/POST /api/graphy/* authMiddleware (admin) Graphy / Mr.Learn proxy + sync
GET/POST /api/ezexam/* authMiddleware (admin) Mr.Test / EzExam sync
POST /api/student/mas101-pap/leegality/start authMiddleware Begin Leegality eSign for PAP agreement
POST /api/student/mas101-pap/leegality/refresh authMiddleware Poll/refresh Leegality signing status
POST /api/sales/mas101-pap/leegality-refresh-token adminMiddleware Refresh Leegality auth token
POST /api/tokens/...verify authMiddleware Verify Razorpay payment signature (token purchase)

Razorpay has no inbound webhook route here — payment confirmation is verified client-roundtrip via HMAC signature (see journey below). Superadmin Razorpay reporting is read-only via RazorpayAdminService.


User journeys

1. Razorpay token purchase (outbound order + signature verify)

No webhook: the frontend opens Razorpay Checkout, then posts the signed result back; the API verifies the HMAC SHA-256 signature server-side before crediting tokens. See src/services/TokenService.ts (order create + verify around lines 49-296) and src/controllers/token.controller.ts.

sequenceDiagram
    participant FE as Frontend
    participant API as Token API
    participant TS as TokenService
    participant RZP as Razorpay
    participant DB as Postgres

    FE->>API: POST create order for N tokens
    API->>TS: createOrder
    TS->>RZP: orders.create amount and receipt
    RZP-->>TS: order id
    TS->>DB: insert TokenPurchase status PENDING
    TS-->>API: order id and key id
    API-->>FE: order id and RAZORPAY_KEY_ID
    Note over FE: Razorpay Checkout collects payment
    FE->>API: POST verify with paymentId orderId signature
    API->>TS: verifyPayment
    TS->>TS: createHmac sha256 over candidate body
    alt signature matches
        TS->>DB: set TokenPurchase COMPLETED and credit tokens
        TS-->>FE: success
    else mismatch
        TS-->>FE: Invalid signature error
    end

2. Exotel click-to-call with status webhook

CRM agent clicks call; the API places a two-leg call via Exotel and gets the final disposition back through the public status webhook. See src/services/ExotelService.ts and src/routes/exotelWebhook.routes.ts.

sequenceDiagram
    participant AGENT as Sales Agent
    participant API as CRM API
    participant EXO as ExotelService
    participant X as Exotel REST
    participant DB as Postgres

    AGENT->>API: POST click-to-call lead id
    API->>EXO: isConfigured check
    alt not configured
        EXO-->>API: not configured
        API-->>AGENT: fall back to tel link
    else configured
        EXO->>X: POST Connect with caller id and StatusCallback url
        X-->>EXO: call sid queued
        EXO->>DB: insert LeadCallLog status initiated
        EXO-->>AGENT: dialing
        Note over X: Exotel bridges agent and lead
        X->>API: POST /api/exotel/call-status with token
        API->>EXO: verifyWebhookToken then handleCallStatus
        EXO->>DB: update LeadCallLog with duration and outcome
        API-->>X: 200 ok
    end

3. WhatsApp send (provider-switched) + inbound webhook

WhatsAppService picks the provider from env or DB config and routes to Meta Cloud Graph API or AiSensy. Delivery/read receipts and inbound replies arrive on the public webhook. See src/services/WhatsAppService.ts and src/routes/whatsapp.routes.ts.

sequenceDiagram
    participant HR as HR or Sales
    participant API as WhatsApp API
    participant WS as WhatsAppService
    participant META as Meta Cloud or AiSensy
    participant DB as Postgres

    HR->>API: POST send template to phone
    API->>WS: send message
    WS->>WS: resolve provider from env or system config
    alt provider meta_cloud
        WS->>META: POST graph messages with access token
    else provider aisensy
        WS->>META: POST aisensy campaign api with api key
    end
    META-->>WS: wa message id
    WS->>DB: insert WhatsAppMessage outbound sent
    WS-->>HR: queued
    Note over META: recipient reads or replies
    META->>API: POST /api/whatsapp/webhook status or inbound
    API->>WS: handleWebhook
    WS->>DB: update WhatsAppMessage status or insert inbound
    API-->>META: 200 ok

4. ElevenLabs / Aarya batch AI calling + async result sync

Admin submits a batch of phone numbers; the API proxies to ElevenLabs Conversational-AI batch calling and stores a batch row. A scheduled sync poller later pulls per-call conversation IDs, durations, and outcomes. See src/services/ElevenLabsBatchService.ts and src/services/AaryaCallSyncService.ts.

sequenceDiagram
    participant ADMIN as Admin
    participant API as Aarya API
    participant EL as ElevenLabsBatchService
    participant E11 as ElevenLabs
    participant SYNC as AaryaCallSyncService
    participant DB as Postgres

    ADMIN->>API: POST submit batch recipients
    API->>EL: createBatch with agent id and phone number id
    EL->>E11: POST batch-calling submit
    E11-->>EL: batch id
    EL->>DB: insert AaryaCallBatch status submitted
    EL-->>ADMIN: submitted count
    Note over SYNC: scheduled poll for non final batches
    SYNC->>E11: GET batch recipients and conversations
    E11-->>SYNC: conversation ids durations outcomes
    SYNC->>DB: update AaryaCallBatch and call rows

5. MissOzone AI voice agent via LiveKit (inbound webhook)

The student talks to an AI agent hosted on the internal LiveKit mas-voice-agent; room and agent lifecycle events post back to a public header-secret webhook. See src/services/MissOzoneService.ts and src/routes/missOzone.routes.ts.

sequenceDiagram
    participant STU as Student
    participant API as MissOzone API
    participant OZ as MissOzoneService
    participant LK as LiveKit voice agent
    participant DB as Postgres

    STU->>API: POST start call
    API->>OZ: create room and token
    OZ->>LK: create room via LIVEKIT_API_BASE
    LK-->>OZ: room and access token
    OZ->>DB: insert MissOzoneCall status started
    OZ-->>STU: room token to join
    Note over LK: agent and student converse
    LK->>API: POST /api/miss-ozone/livekit-webhook with secret
    API->>OZ: verify webhook secret then handle event
    OZ->>DB: update MissOzoneCall status and transcript
    API-->>LK: 200 ok

6. Leegality PAP e-sign (outbound + polling refresh)

The PAP/MOU agreement is sent to Leegality for e-signing; because the sandbox has no reliable inbound callback here, the client refreshes status by polling a refresh endpoint that re-queries Leegality. See src/services/LeegalitySandboxService.ts and src/services/Mas101PapWorkflowService.ts.

sequenceDiagram
    participant STU as Student
    participant API as PAP API
    participant WF as Mas101PapWorkflowService
    participant LEE as LeegalitySandboxService
    participant L as Leegality eSign
    participant DB as Postgres

    STU->>API: POST leegality start
    API->>WF: startLeegalitySigning
    WF->>LEE: createSignRequest with auth token
    LEE->>L: POST sign request from template
    L-->>LEE: document id and sign url
    WF->>DB: store document id status sent_for_signing
    WF-->>STU: redirect to sign url
    Note over STU: student signs on Leegality
    STU->>API: POST leegality refresh
    API->>WF: refreshLeegalitySigning
    WF->>LEE: GET status by document id
    LEE->>L: GET document status
    L-->>LEE: signed and file url
    WF->>DB: update workflow signed pending admin review
    WF-->>STU: signed

7. Judge0 code execution (public proxy)

Quiz/assignment pages run student code through a self-hosted Judge0 instance proxied by the API (so the page never sees the Judge0 host). See src/controllers/judge0.controller.ts.

sequenceDiagram
    participant FE as Quiz Page
    participant API as Judge0 proxy
    participant J as Judge0

    FE->>API: POST run-tests with source and test cases
    loop each test case
        API->>J: POST submissions base64 false wait true
        J-->>API: stdout stderr status
    end
    API-->>FE: per test results
    Note over API: on Judge0 unreachable returns Failed to reach Judge0 API

Background jobs & async

  • Email is never sent inline — EmailService work is enqueued onto emailQueue and run by src/workers/email.worker.ts (Nodemailer/Gmail SMTP). Redis backs all BullMQ queues (src/config/redis.ts).
  • Aarya/ElevenLabs syncAaryaCallSyncService periodically polls non-final batches for conversation results (scheduled job).
  • Mr.Learn / Mr.Test syncMrLearnSyncService and MrTestSyncService pull learner progress and exam submissions from Graphy/EzExam on a schedule into the mrlearn.* / mrtest.* schemas.
  • Global payment syncGlobalPaymentSyncService pages through Razorpay payments (read-only) to mirror them into superadmin.global_payments for finance reporting.
  • Inbound webhooks (vendor → API): /api/exotel/call-status, /api/whatsapp/webhook, /api/miss-ozone/livekit-webhook, plus the Google OAuth redirect callbacks. All return HTTP 200 even on internal failure (for Exotel) to avoid vendor retries hammering the API.

External integrations

Full catalog. "Direction" = Out (API calls vendor), In (vendor calls API webhook), or both.

Integration Wrapper service Direction Env vars Fallback
Razorpay (payments) src/services/TokenService.ts, src/services/RazorpayAdminService.ts, src/services/GlobalPaymentSyncService.ts Out (+ client signature roundtrip) RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET SDK = null; token purchase "limited"; admin/sync throws "Razorpay is not configured". See token-economy, payments-finance-gst
Google OAuth / Calendar / Meet src/services/GoogleAuthService.ts, src/services/GoogleCalendarService.ts Out + In (OAuth callback) GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI, APPLICATION_MEETING_TIME_ZONE, FRONTEND_URL Tokens in GoogleAuthTokens; meeting falls back to non-Meet link if unconfigured. See mentorship-and-meetings
Google Drive src/services/GoogleDriveConnectorService.ts, src/services/GoogleDriveService.ts Out + In (callback) GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_DRIVE_REDIRECT_URI Connector disabled until OAuth completed
AWS S3 + CloudFront src/services/S3Service.ts, src/services/s3Uploader.service.ts Out (+ presigned direct upload) AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_S3_BUCKET_NAME, AWS_S3_STUDENT_DOCUMENTS_BUCKET, AWS_S3_BANNER_ASSETS_BUCKET, MISS_OZONE_ARCHIVE_BUCKET, MAS_ASSETS_CDN_URL, GLOBAL_INVOICE_S3_BUCKET Uploads fail loudly; recordings use presigned direct-to-S3 (USE_DIRECT_S3_UPLOAD). See mentorship-and-meetings
Exotel (calls + SMS) src/services/ExotelService.ts, src/services/ExotelLeadService.ts Out + In (/api/exotel/call-status) EXOTEL_SID, EXOTEL_API_KEY, EXOTEL_API_TOKEN, EXOTEL_CALLER_ID, EXOTEL_SUBDOMAIN, EXOTEL_SMS_SENDER_ID, EXOTEL_WEBHOOK_TOKEN, BACKEND_PUBLIC_URL isConfigured() false → CRM uses tel: links; webhook rejects bad token with 403. See comms-telephony-exotel
WhatsApp (Meta Cloud / AiSensy) src/services/WhatsAppService.ts, src/services/LeadWhatsAppService.ts Out + In (/api/whatsapp/webhook) WHATSAPP_PROVIDER, WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_BUSINESS_ACCOUNT_ID, WHATSAPP_GRAPH_API_VERSION, WHATSAPP_WEBHOOK_VERIFY_TOKEN, WHATSAPP_CREDENTIALS_ENCRYPTION_KEY, PLATFORM_ENCRYPTION_KEY; AISENSY_API_KEY from system-config DB Provider switch (meta_cloud default); per-user creds in WhatsAppConfig. See comms-whatsapp
Nodemailer / Gmail SMTP src/services/EmailService.ts (via emailQueue worker) Out EMAIL_USER, EMAIL_PASS, EMAIL_FROM, EMAIL_TIMEOUT_MS, MENTOR_ONBOARDING_CC_EMAIL, STUDENT_ONBOARDING_CC_EMAIL If EMAIL_USER/EMAIL_PASS missing → warns "Email SMTP not configured" and no-ops (logs would-send). See comms-email-and-notifications
ElevenLabs + Aarya (AI calling) src/services/ElevenLabsBatchService.ts, src/services/AaryaCallSyncService.ts Out (poll for results) ELEVENLABS_API_KEY, AARYA_AGENT_ID, AARYA_PHONE_NUMBER_ID Admin-only proxy; no calls submitted without key. See mr-hire-voice-interviews-and-ai-calling
MissOzone / LiveKit (AI voice agent) src/services/MissOzoneService.ts Out + In (/api/miss-ozone/livekit-webhook) LIVEKIT_API_BASE, LIVEKIT_WEBHOOK_SECRET, PUBLIC_BASE_URL Internal-only agent on mas-network; webhook rejects bad secret. See mr-hire-voice-interviews-and-ai-calling
LLM Gateway (LiteLLM) src/services/LlmGatewayService.ts Out LITELLM_BASE_URL (default http://mas-llm-gateway:4000), LITELLM_MASTER_KEY, LITELLM_ADMIN_TIMEOUT_MS, LLM_GATEWAY_ENCRYPTION_KEY, PLATFORM_ENCRYPTION_KEY Per-user virtual key in UserLlmKey (encrypted); master key only for admin /key/generate. See workflow-automation-engine
Groq (Ask MAS assistant) src/services/AskMasService.ts Out GROQ_API_KEY, GROQ_TEXT_MODEL, GROQ_TEXT_ENDPOINT, GROQ_TIMEOUT_MS, ASKMAS_GATEWAY_MODEL, ASKMAS_USER_* budgets Endpoints return HTTP 503 until GROQ_API_KEY set. See student-portal-and-profile
Graphy / Mr.Learn (mrlearn.in) src/services/GraphyLmsService.ts, src/services/MrLearnSyncService.ts, src/services/MrLearnReminderService.ts Out GRAPHY_BASE_URL (default https://www.mrlearn.in), JWT_SECRET; session creds in mrlearn.auth_credentials (AES-256-GCM) No SDK — proxies Graphy browser APIs; 401/403 surfaced from /api/graphy/*. See integration-mr-learn
Mr.Test / EzExam src/services/MrTestSyncService.ts, src/services/EzExamService.ts Out EZEXAM_BASE_URL, JWT_SECRET; base URL + creds also in MrTestSyncConfig Per-exam sync config; mounted /api/ezexam. See integration-mr-test
Judge0 (code execution) src/controllers/judge0.controller.ts Out (proxy) JUDGE0_API_URL (default http://localhost:2358) Returns "Failed to reach Judge0 API" on connection error. See assessments-quizzes-assignments
Leegality (e-sign) src/services/LeegalitySandboxService.ts, src/services/Mas101PapWorkflowService.ts Out (poll refresh) LEEGALITY_SANDBOX_BASE_URL (default https://sandbox.leegality.com/api), LEEGALITY_SANDBOX_AUTH_TOKEN, MAS101_LEEGALITY_SANDBOX_CREATE_REQUEST_TEMPLATE, MAS_WEBSITE_URL; or DB system-config fallback Three-tier config resolution env → DB → default; auth token via admin refresh endpoint. See documents-esign-and-agreements
Redis src/config/redis.ts Out REDIS_HOST, REDIS_PORT (REDIS_PASSWORD/REDIS_DB commented out) Required for BullMQ; absence breaks queues/workers
mr-hire-backend (internal) src/services/VoiceInterviewService.ts Out MR_HIRE_BACKEND_URL, MR_HIRE_FRONTEND_URL Empty default → voice-interview sync no-ops. See mr-hire-voice-interviews-and-ai-calling

Status lifecycles

Leegality PAP signing (per Mas101PapWorkflowService)

stateDiagram-v2
    [*] --> pending_mou_upload
    pending_mou_upload --> sent_for_signing : startLeegalitySigning
    sent_for_signing --> sent_for_signing : refresh still pending
    sent_for_signing --> signed : Leegality reports complete
    signed --> pending_admin_review : MOU stored to S3
    pending_admin_review --> approved : admin verifies
    approved --> [*]

Exotel / Aarya call disposition

stateDiagram-v2
    [*] --> initiated
    initiated --> ringing
    ringing --> in_progress : answered
    ringing --> no_answer : missed
    in_progress --> completed
    initiated --> failed : Exotel error
    completed --> [*]
    no_answer --> [*]
    failed --> [*]

Edge cases, limits & gotchas

  • Razorpay has no webhook here. Confirmation relies on the client posting back the signature; verifyPayment tries multiple HMAC formulas to cover both order-flow and invoice-flow signatures (TokenService.ts ~lines 252-290). A mismatch returns "Invalid signature" and tokens are not credited. Idempotency hinges on the TokenPurchase row status.
  • Webhook secrets, not JWT. Exotel (?token=), WhatsApp (verify token), and LiveKit (header secret) authenticate the vendor. These routes are deliberately outside authMiddleware. Exotel's webhook always answers 200 (even on internal failure) to stop Exotel retry storms — failures are logged, not surfaced.
  • EXOTEL_SUBDOMAIN must match the account's cluster (e.g. api.exotel.com vs api.in.exotel.com) or every call/SMS 401s. Dev and prod use separate Exotel accounts.
  • WhatsApp provider resolution order: env WHATSAPP_PROVIDER first, then system-config DB; meta and meta_cloud both map to Meta Cloud. AiSensy key comes only from the system-config table, not env.
  • DB-stored, encrypted credentials for Graphy (mrlearn.auth_credentials), WhatsApp (WhatsAppConfig), and LiteLLM (UserLlmKey) use AES-256-GCM keyed by PLATFORM_ENCRYPTION_KEY / WHATSAPP_CREDENTIALS_ENCRYPTION_KEY / LLM_GATEWAY_ENCRYPTION_KEY. Rotating those keys orphans existing ciphertext.
  • LiteLLM base URL is the internal Docker hostname http://mas-llm-gateway:4000 (no TLS, same mas-network); the master key is used only for admin key-minting, never for per-user inference.
  • Graphy/Mr.Learn has no official SDK or embed. Everything is a server-side replay of Graphy's own browser endpoints (/s/authenticate, /s/microservice/token); a session-cookie expiry shows up as 401/403 on /api/graphy/* and needs a re-auth.
  • Email is fully async. A missing SMTP credential will not error the request — it logs a warning and silently drops the mail. Watch for 535-5.7.8 BadCredentials after Gmail app-password rotation; queued jobs do not auto-retry.
  • Judge0 default is localhost:2358. In prod this must point at the deployed Judge0 or every run-tests call returns the unreachable error.
  • Multi-tenant header. Requests carry x-platform (mr-mentor / my-analytics-school); integration behavior is generally platform-agnostic but URLs in emails/links derive from FRONTEND_URL / MAS_WEBSITE_URL.
  • Secrets live in AWS Secrets Manager for deploys (mr-mentor-backend/{development,production}, ap-south-1), not in committed .env. The .env.example documents only a subset; many integration vars (Exotel, LiveKit, LiteLLM, Leegality, ElevenLabs, Judge0, Graphy, EzExam) are read directly in code and must be set in SM.