Integrating enterprise software is one of those things that looks simple until you're three months in and realizing that every system has a different opinion about what a "customer" is.
At eZhire, we've integrated 10+ enterprise systems into a unified platform. Some integrations went smoothly. Several didn't. This is what we learned.
The Integration Landscape
Here's what we integrated, and why:
| System | Category | Why |
|---|---|---|
| Oracle NetSuite | ERP / Finance | Accounting, revenue recognition, financial reporting |
| Checkout.com | Payments | Card processing, refunds, payment links |
| ZATCA | Tax Compliance | UAE tax authority compliance |
| HubSpot | CRM | Lead management, pipeline, sales automation |
| Crisp | Live Chat | Website and in-app chat |
| BotSpace | WhatsApp Business API automation | |
| Ziwo | Call Center | Telephony, IVR, call recording |
| Aswat | Voice Analytics | Call transcription and analytics |
| Firebase | Mobile | Push notifications, mobile backend |
| Slack | Notifications | Internal alerting and notifications |
| ClearGrid | Collections | Debt collection workflow automation |
Eleven systems. Different APIs. Different authentication patterns. Different data models. Different failure modes.
Principle 1: Async Is Your Friend
The biggest mistake teams make with integrations is treating them as synchronous operations.
User books a car → sync to NetSuite → return success.
This works until NetSuite is having a bad day. Then your booking API starts timing out, customers can't complete bookings, and your on-call engineer is getting paged at 2am.
The correct pattern for almost all third-party integrations is:
- Record the event in your own system (fast, reliable)
- Return success to the user
- Asynchronously sync to the third-party system
- Retry failures with exponential backoff
- Alert on persistent failures for manual intervention
We implemented this pattern across all our integrations after learning the hard way with our initial NetSuite sync implementation.
Principle 2: Own the Data Model
Every integration wants you to adopt its data model. NetSuite wants customers to be NetSuite customers. HubSpot wants leads to be HubSpot contacts. Checkout.com wants transactions to be Checkout.com charges.
Don't do this.
Your canonical data model should live in your system. Third-party systems get their own representation of your data, synchronized from your canonical store.
This means:
- A customer in our system has a
netsuite_customer_id, ahubspot_contact_id, and acheckout_customer_id - When we look up a customer, we look in our database — not NetSuite
- When we sync to NetSuite, we transform our customer model into NetSuite's model
This sounds like extra work. It is. But it means that when you switch CRM providers (and you will, eventually), you're changing one sync adapter, not your entire data model.
Principle 3: Build Idempotent Sync
Network failures happen. Servers restart. Webhooks are delivered multiple times. Your sync logic will run more than once for the same event.
If your sync logic isn't idempotent — meaning it produces the same result whether it runs once or a hundred times — you'll create duplicate data, double-charged customers, or corrupted financial records.
Every sync operation should:
- Check if the target already has this data
- If yes, compare and update if changed
- If no, create
Simple in principle. Surprisingly hard to implement correctly when dealing with complex nested data structures across different system schemas.
The NetSuite Integration: Our Hardest
NetSuite integration is a rite of passage for enterprise software teams. It's comprehensive, flexible, and genuinely complex.
Our NetSuite integration handles:
- Customer records (created/updated on booking)
- Invoice generation (rental period, extensions, late fees)
- Payment recording (from Checkout.com webhooks)
- Revenue recognition (rental period-based)
- Credit notes (refunds, adjustments)
- Collection records (overdue account status)
The hardest part was revenue recognition. A car rental spans multiple days. Revenue needs to be recognized daily, not at booking time. This required building a nightly job that creates journal entries in NetSuite for each active rental day.
Getting this right required 3 months of parallel running — our system and the old manual process running simultaneously — before finance was confident enough to switch over.
Checkout.com: Payment Webhooks Are Lies
Webhook reliability is a known problem in the industry. Checkout.com's documentation says webhooks are reliable. In practice, they're delivered at-least-once, sometimes delayed, and occasionally dropped.
Our payment processing is built around a polling fallback:
- Record payment initiation
- Receive webhook if/when it arrives
- Every 15 minutes, poll for any payments that are in "pending" state for more than 10 minutes
- Reconcile the payment status from the Checkout.com API directly
This redundancy means we have a brief window where a payment might appear pending, but we never miss a successful payment.
HubSpot + BotSpace + Crisp: The Lead Chaos Problem
Three different systems, all generating leads. A customer might:
- Fill out the website form (HubSpot)
- Chat on the website (Crisp)
- Message on WhatsApp (BotSpace)
Without integration, you get three records in three systems for the same person.
We built a lead unification layer that:
- Captures leads from all three sources
- Deduplicates by phone number and email
- Creates a canonical lead record in our ERP
- Syncs back to HubSpot as the system of record for sales
- Links the Crisp and BotSpace conversation IDs to the lead record
The deduplication logic is the hard part. Phone numbers come in different formats. Emails are sometimes missing. Names are sometimes different. We use fuzzy matching with manual review queues for ambiguous cases.
Monitoring Integrations
Every integration should have:
- Sync queue depth — how many events are waiting to sync?
- Sync error rate — what percentage of syncs are failing?
- Sync latency — how long does it take from event to sync?
- Last successful sync — when did each integration last successfully process an event?
We built a simple integration health dashboard that shows these metrics for each of our 11 integrations. When something goes red, we know about it before a customer or executive notices.
What I'd Do Differently
Design the failure handling before the happy path. It's tempting to build the integration that works and then add error handling. Do it the other way around. Start with "what happens when the third-party system is down?" and build from there.
Be paranoid about data loss. Every event that enters your sync queue should be durably stored before you attempt to sync it. If your sync process dies mid-flight, you need to be able to replay from the durable store.
Version your integration contracts. External APIs change. Build your integration adapters to be versioned, so you can upgrade to a new API version while maintaining the old one during transition.
Enterprise integration is unglamorous work. Nobody writes blog posts celebrating a clean NetSuite sync. But it's the foundation that makes everything else work — and getting it right separates platforms that scale from platforms that constantly break.