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 shouldnew-up a vendor SDK orfetcha 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.provider∈meta_cloud | aisensy;WHATSAPPMESSAGE.direction∈outbound | 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 —
EmailServicework is enqueued ontoemailQueueand run bysrc/workers/email.worker.ts(Nodemailer/Gmail SMTP). Redis backs all BullMQ queues (src/config/redis.ts). - Aarya/ElevenLabs sync —
AaryaCallSyncServiceperiodically polls non-final batches for conversation results (scheduled job). - Mr.Learn / Mr.Test sync —
MrLearnSyncServiceandMrTestSyncServicepull learner progress and exam submissions from Graphy/EzExam on a schedule into themrlearn.*/mrtest.*schemas. - Global payment sync —
GlobalPaymentSyncServicepages through Razorpay payments (read-only) to mirror them intosuperadmin.global_paymentsfor 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;
verifyPaymenttries 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 theTokenPurchaserow status. - Webhook secrets, not JWT. Exotel (
?token=), WhatsApp (verify token), and LiveKit (header secret) authenticate the vendor. These routes are deliberately outsideauthMiddleware. Exotel's webhook always answers 200 (even on internal failure) to stop Exotel retry storms — failures are logged, not surfaced. EXOTEL_SUBDOMAINmust match the account's cluster (e.g.api.exotel.comvsapi.in.exotel.com) or every call/SMS 401s. Dev and prod use separate Exotel accounts.- WhatsApp provider resolution order: env
WHATSAPP_PROVIDERfirst, then system-config DB;metaandmeta_cloudboth 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 byPLATFORM_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, samemas-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 BadCredentialsafter 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 fromFRONTEND_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.exampledocuments 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.
Related docs¶
- System context & containers
- System design
- Integrations hub
- Payments, finance & GST
- Token economy
- Telephony (Exotel)
- Email & notifications
- Voice interviews & AI calling
- E-sign & agreements
- Mr.Learn integration
- Mr.Test integration
- Mentorship & meetings
- Assessments, quizzes & assignments
- Workflow automation engine
- Vendor API platform