All Docs
FeaturesNurtureHubUpdated March 21, 2026

Behind the Build: CRM Integration Adapter Base Layer (v1.0.39)

Behind the Build: CRM Integration Adapter Base Layer

v1.0.39 — Engineering deep-dive

NurtureHub is built to connect natively to agentOS and via open API to every major proptech CRM in the UK market — Reapit, Alto, Street, Loop, and beyond. Shipping reliable, maintainable integrations at that scale without accumulating an unmanageable web of bespoke glue code requires a disciplined architectural foundation. That's exactly what v1.0.39 delivers.


The Problem with Ad-Hoc Integrations

Without a shared contract, each CRM connector tends to grow its own conventions: different credential handling, different sync strategies, different ways of mapping contacts, different error handling. The result is a codebase where adding a fifth integration is just as hard as adding the first — and where a bug fix in one connector doesn't benefit the others.

We wanted the opposite: a model where each new CRM integration costs less than the last, and where correctness guarantees in the shared layer propagate to every connector automatically.


Ports and Adapters (Hexagonal Architecture)

v1.0.39 implements the Ports and Adapters pattern (also known as Hexagonal Architecture) for all CRM connectivity.

The key idea is a strict separation between:

  • The port — an abstract interface defining what the platform needs from any CRM: sync contacts, push activity, ingest webhooks, verify a connection.
  • The adapters — concrete implementations of that interface, one per CRM provider, each responsible for translating between the CRM's specific API and NurtureHub's canonical data models.

Core platform logic — nurture sequencing, intent scoring, lead alerting — talks exclusively to the port. It has no knowledge of any individual CRM. Adding Reapit support means writing a Reapit adapter. Adding Alto support means writing an Alto adapter. Neither touches the core.


What Ships in This Release

The Abstract Adapter Interface

The interface defines four methods that every CRM adapter must implement:

MethodPurpose
syncContactsPull contacts from the CRM and reconcile them into NurtureHub
pushActivityWrite email engagement and nurture events back to the CRM
ingestWebhookReceive and process real-time event payloads pushed by the CRM
verifyConnectionValidate stored credentials and confirm connectivity

Any class implementing this interface is a valid CRM adapter. The platform treats them all identically.

CRM Provider Registry

A provider registry table enumerates every CRM NurtureHub knows about. When a new adapter is written and merged, its provider is registered here. Routing logic that resolves which adapter to instantiate for a given tenant reads from this registry — meaning no core routing code changes when a new CRM is added.

Per-Tenant Connection Records

Each agency that connects a CRM gets a dedicated connection record containing:

  • Encrypted credentials — API keys, OAuth tokens, or whatever the CRM requires, stored encrypted at rest
  • Sync cursor — a position marker (timestamp, sequence ID, or similar) that tells the adapter where incremental sync should resume, preventing duplicate processing across runs
  • Provider reference — links the connection to the correct adapter via the registry

Canonical Data Models

Rather than letting each adapter define its own output shape, all adapters map their CRM-specific objects into two shared canonical schemas:

Contact — a normalised contact record covering the fields NurtureHub needs regardless of which CRM the contact originated from: identity, contact details, assigned category, and provenance metadata.

Activity — a normalised event record covering email sends, opens, clicks, and CRM-side activities such as calls or viewings, with a consistent timestamp and source attribution.

Because all adapters produce the same shapes, the rest of the platform can process contacts and activities without branching on CRM type.

Connection Health Monitoring

Every connection record now carries health tracking fields:

  • lastSyncedAt — timestamp of the most recent successful sync run
  • lastErrorAt / lastErrorMessage — timestamp and message of the most recent failure

This data is the foundation for the connection health UI and for future alerting when a sync has been failing for an extended period.


Extending the Platform

The intended workflow for adding a new CRM integration is:

  1. Write a new adapter class implementing the abstract interface
  2. Register the new provider in the CRM provider registry
  3. Map the CRM's contact and activity objects to the canonical schemas within the adapter
  4. Deploy — no changes required anywhere else in the platform

This is the extension point for all CRM integrations going forward.


What's Next

With the adapter base layer in place, concrete CRM adapters — starting with agentOS and Reapit — can be built on top of it. Each one will implement the four-method interface, produce canonical contacts and activities, and slot into the platform's sync and health-monitoring infrastructure automatically.