The Challenge
Universities are complex organisations. A single student's journey — from prospective applicant to enrolled graduate — touches a dozen different systems. At the University of London, that journey starts in Salesforce, where every application, qualification, and enrolment is tracked. It ends in SITS, the student records system that governs timetabling, fees, and academic history. In between sit Canvas (the learning management system), Digitary (digital credentialing), and Parchment (transcript services).
The problem? These systems don't talk to each other.
Historically, data moved between them through batch processes, manual exports, and fragile point-to-point integrations. An applicant accepted in Salesforce might take hours — or days — to appear in SITS. Enrolment changes in Canvas had no way to reach Salesforce. Assessment results were siloed. The operational overhead was significant, and the risk of data inconsistency was ever-present.
The University of London needed a central nervous system — a platform that could receive events in real time, transform them, and deliver them to every downstream system that cared. That's what we built.
The Vision: An Event-Driven Integration Platform
We designed a central data mesh sitting between Salesforce and every downstream system. Rather than building brittle point-to-point connections, we created a hub-and-spoke architecture where:
- Salesforce is the source of truth for applicant and application data
- The integration platform receives changes in real time, normalises them, and publishes them to a message bus
- Downstream consumers (SITS, Canvas, Digitary, Parchment) subscribe to the events they care about
- Cosmos DB maintains a persistent, queryable state of every entity — students, enrolments, courses, assessments, applicants, and applications
The result is a system where a single event in Salesforce — an application submitted, a qualification verified, an enrolment confirmed — propagates instantly to every system that needs it.
The Technology: Modern, Scalable, and Proudly Python
Salesforce Pub/Sub API (gRPC)
The heart of the platform is a always-on Python service that maintains a persistent gRPC connection to Salesforce's Pub/Sub API. Unlike traditional polling approaches, the Pub/Sub API pushes events to the listener the moment they occur. We subscribe to custom platform events that fire whenever an applicant's status changes in Salesforce.
The listener is built with FastAPI and runs as an Azure Web App with uvicorn. It's not a traditional Azure Function — it's a long-running service that manages gRPC streams, handles reconnection logic, and persists replay checkpoints to Cosmos DB so that no event is lost during restarts or deployments.
Azure Service Bus: The Message Backbone
Once the listener processes a Salesforce event, it publishes a normalised message to Azure Service Bus. We defined a set of topics, each representing a domain entity — students, enrolments, courses, assessments, applicants, and applications. Each topic has multiple subscriptions, allowing different consumers to receive the same event independently.
Canvas listens to student and enrolment events. SITS listens to applicant and application events. Digitary and Parchment listen to assessment events. Salesforce itself receives writebacks through dedicated applicant and application topics.
This decoupled design means adding a new downstream system is as simple as creating a new subscription — no changes to the publisher.
Azure Cosmos DB: The State Store
Every entity in the platform has a home in Cosmos DB. We provisioned dedicated containers across entity, history, and lease partitions. The Change Processor reads the Cosmos DB change feed, detects entity modifications, and publishes them to Service Bus — creating a fully reactive pipeline where a write to Cosmos DB triggers downstream notifications automatically.
Replay checkpoints are stored in a dedicated container, ensuring the gRPC listener can resume exactly where it left off after any interruption. A separate audit container with a time-to-live policy provides operational visibility into every event processed.
Azure API Management: The Front Door
External systems like SITS interact with the platform through Azure API Management (APIM). We configured multiple APIs with JWT validation, rate limiting, and subscription key authentication. SITS can call a REST endpoint to update applicant records in Salesforce asynchronously — the request is accepted immediately (HTTP 202), and the actual Salesforce update is queued through Service Bus to a dedicated patcher service, ensuring ordered, reliable delivery.
Managed Identity and Key Vault
Security was a first-class concern. Every Function App uses system-assigned managed identity for Service Bus and Cosmos DB access — no connection strings in configuration files. Secrets like Salesforce client credentials, SITS subscription keys, and exception logger codes are stored in Azure Key Vault and referenced through Key Vault bindings. The platform supports multiple environments (development, sandbox, testing, UAT, QA, production, and disaster recovery), each with its own isolated Key Vault and resource groups.
The Architecture in Practice
Here's what happens when an applicant submits an application in Salesforce:
- Salesforce fires a platform event — the integration listener receives it instantly via gRPC
- The listener processes and validates the payload — transforming it into a normalised internal format
- The Change Processor picks up the entity change — writes to Cosmos DB and publishes to Service Bus
- Service Bus fans out the event — SITS, Canvas, and awarding body consumers all receive it simultaneously
- SITS Update Consumer sends the application to SITS — via APIM, with subscription key authentication
- Canvas Listeners create and update student records — enrolling students in courses, managing sections
- If assessment results come back — Digitary and Parchment consumers generate digital credentials and transcripts
- If SITS updates the applicant — the change flows back through APIM to the listener, which queues an update to Salesforce via the patcher service
The entire flow — from Salesforce event to SITS record update — completes in seconds, not hours.
Overcoming Real-World Challenges
This wasn't a textbook deployment. We hit — and solved — significant engineering challenges along the way:
Azure App Service health checks and startup sequencing. The listener needs to initialise gRPC connections, Cosmos DB clients, and Service Bus publishers before it can serve traffic. Azure's health check has a strict timeout — if the app doesn't respond quickly, the platform recycles the container. We solved this by ensuring the web server starts immediately and lightweight initialisation runs in FastAPI's startup events, with heavy service initialisation deferred to background tasks.
APIM deployment conflicts during migration. When migrating from a legacy web app to the new listener, APIM API resources clashed with existing configurations. We built cleanup logic into the deployment pipeline that identifies and removes stale APIM APIs and backends before redeploying — ensuring a clean state without manual intervention.
Key Vault migration at scale. The platform evolved from manual secret configuration to full Key Vault integration. We migrated over a dozen Function Apps to use Key Vault references, each requiring access policy grants and placeholder secret deployment. The migration was done incrementally, environment by environment, with git revert as the rollback strategy.
Service Bus session ordering. The patcher service processes update commands to Salesforce in ordered sessions, ensuring that if SITS sends multiple updates for the same applicant, they're applied in sequence. This required session-aware Service Bus subscriptions and careful dead-letter handling.
The Numbers
| Metric | Value |
|---|---|
| Web & Function Apps deployed | 24 |
| Service Bus topics | 8 |
| Cosmos DB containers | 24 |
| APIM APIs | 10 |
| Infrastructure as Code files | 50 |
| Environments supported | 7 |
| Downstream systems integrated | 5 (SITS, Canvas, Digitary, Parchment, Salesforce writeback) |
| Event latency (Salesforce → SITS) | Seconds |
| Infrastructure deployment time | ~5 minutes |
Why We're Proud
This isn't just a set of integrations. It's a platform — one that scales horizontally, handles failures gracefully, and can absorb new downstream systems without architectural changes. It's built on open standards (gRPC, OAuth 2.0, OpenAPI), runs on serverless and consumption-based Azure infrastructure, and is fully managed through Infrastructure as Code.
The University of London now has a real-time, event-driven integration backbone that connects their entire student journey — from the moment an application is submitted in Salesforce to the day a digital credential is issued. No batch jobs. No manual exports. No data silos.
That's the kind of engineering we're proud of at Real Code Ltd.
This article was written by the Real Code Ltd engineering team. For more information about our work with Azure, Salesforce, and enterprise integrations, visit realcode.co.uk.
