← Back

Integrating a nurse scheduling platform with Bullhorn — six months as an embedded fractional CTO

embedded fractional CTO · 6 months

A nursing agency network ran its own scheduling platform for matching part-time nurses to hospital shifts. The product worked, but it lived in a separate world from Bullhorn, their ATS/CRM — candidates, clients, and placements on one side, actual shifts on the other, with staff manually re-entering data between the two.

I was brought in for two jobs at once: build a deep Bullhorn integration end-to-end, and act as fractional CTO for shareholders who had ambitious plans but no unified technical direction. The engagement ran six months, delivered autonomously.

The decisions that mattered

Polling, because there was no other option

Bullhorn offered no webhooks for what we needed, so real-time sync was off the table from day one. The only engineering answer left was a polling-based synchronization layer — which turns "sync the systems" into a series of less glamorous decisions: how often to poll each entity type against API rate limits, how to detect what actually changed, and how to make every update idempotent so a re-processed record could never corrupt data.

Part of the job was also setting expectations: leadership had to understand the systems would be consistent within minutes, not instantly, and why that was a platform constraint rather than a shortcut.

Two data models that disagreed about reality

Bullhorn thinks in candidates, clients, and placements. The scheduling platform thought in nurses, hospitals, and shifts. These sound like synonyms; they aren't — the boundaries and lifecycles differ, and pretending otherwise creates duplicate records and unclear ownership.

The core design work was mapping the two models and deciding, per entity and per field, which system was the source of truth. Bullhorn remained the record of truth for engagements; the platform owned scheduling reality. Keeping that boundary explicit is what kept the sync from degenerating into two systems overwriting each other.

The hard part that wasn't code

Getting onto Bullhorn's marketplace involved substantial red tape — partner approval, compliance requirements, process. It's a real cost of any deep ATS/CRM integration — one that estimates usually ignore. Navigating it was part of the delivery, not an interruption to it.

The advisory track

In parallel, I worked with the shareholders as fractional CTO: shaping the 12–24 month roadmap, separating what to build next from what to postpone, and defining boundaries between core scheduling logic, integrations, and UI so future developers could onboard without archaeology.

What changed

  • Staff stopped manually reconciling data between Bullhorn and the scheduling platform; records flowed in one direction of truth.
  • The integration shipped as designed within the six-month engagement, built and delivered with minimal supervision.
  • Leadership left with a realistic technical roadmap instead of a wishlist.
Technical notes
  • Laravel, built as a separate integration module with its own API surface — deliberately decoupled so changes on either side wouldn't force a rewrite.
  • Polling-based sync with change detection, idempotent processing, and rate-limit awareness; logging and monitoring so failures could be investigated rather than guessed at.
  • Error handling designed for partial failure: one bad record doesn't stall the pipeline.
  • Engagement: ~6 months, fully autonomous delivery, combined hands-on build with shareholder-level advisory.