Skip to main content

Sync NAV <> HubSpot

1. Grundstruktur des Sync-Services

Das Repository hopsteiner-businesscentral2HubSpot ist ein Express API Service, der als Middleware zwischen NAV (Business Central) und HubSpot fungiert.

Architektur

NAV (Business Central)

│ REST API

Express Sync Service

│ HubSpot API

HubSpot CRM

Der Service hat zwei Aufgaben:

RichtungBeschreibung
NAV → HubSpotDaten aus NAV holen und in HubSpot speichern
HubSpot → NAVÄnderungen aus HubSpot über Webhooks zurück nach NAV senden

2. NAV → HubSpot (Hauptfluss)

Das passiert über diese Routes:

routes.post(`/sync-companies`, handleCustomers);
routes.post(`/sync-salescontracts`, handleSalesContracts);
routes.post(`/sync-msos`, handleMSOs);
routes.post(`/sync-postedinvoices`, handlePostedInvoices);
routes.post(`/sync-swss`, handleSWSs);
routes.post(`/sync-swslines`, handleSWSLines);
routes.post(`/sync-msolines`, handleMSOLines);
routes.post(`/sync-postedinvoicelines`, handlePostedInvoiceLines);

Diese Endpunkte starten jeweils einen Sync-Controller.

Beispiel:

// Customers - Companies(HS)
const handleCustomers = async ({ interval }) => {
try {
const handleDBCustomers = async (interval) => {
let isNextPage = false;
// API filter: ?$top=5&$filter=Last_Modified_Date_Time gt 2023-10-01T20:42:15Z

let formattedDate;
let url;
if (interval === "daily") {
formattedDate = moment()
.utc()
.subtract(2, "days")
.format("YYYY-MM-DDTHH:mm:ss[Z]");
console.log("interval", interval, formattedDate);
url = `${MS_API_URL}/Hubspot_APIs_Customers?$filter=Last_Modified_Date_Time gt ${formattedDate}`;
} else {
console.log("interval", interval);
url = `${MS_API_URL}/Hubspot_APIs_Customers`;
}
...
}
...
}
}

Was das bedeutet:

  • MS_API_URL ist die Basis einer Microsoft-/NAV-/Business-Central-API
  • Hubspot_APIs_Customers klingt sehr stark nach einem eigens angelegten API-Endpunkt
  • der Zusatz ?$filter=... ist typisch OData-Syntax, wie sie bei NAV / Business Central oft verwendet wird
  • auch @odata.nextLink im Response bestätigt, dass das sehr wahrscheinlich ein OData-Webservice ist

Warum das so dafür spricht:

  • der Endpoint-Name Hubspot_APIs_Customers sieht nicht nach Standard-HubSpot aus, sondern nach einer kundenspezifischen NAV/Business-Central API/Page/Webservice
  • Felder wie Last_Modified_Date_Time, No, Salesperson_Email, Hubspot_Company_No wirken wie typische NAV-/BC-Feldnamen
  • die Daten werden zuerst aus dieser Microsoft-API gezogen und dann lokal in MongoDB gespeichert (Customer.findOneAndUpdate(...))
  • danach werden sie nach HubSpot synchronisiert

3. Ablauf eines Sync-Prozesses

Der Ablauf ist immer gleich aufgebaut.

  1. Daten aus NAV API holen

Beispiel (typischer NAV Request):

${MS_API_URL}/Hubspot_APIs_MSO_Lines?$filter=Last_Date_Modified gt ${formattedDate}

Das ist eine Business Central Web API.

  1. Die API liefert Daten aus Tabellen wie:
NAV TabelleZweck
VendorGrower / Company
Sales ContractVerträge
MSOVerkaufsaufträge
MSO LinesAuftragspositionen
Posted InvoiceRechnungen
Posted Invoice LinesRechnungspositionen
  1. Die API liefert JSON.

Beispiel:

{
"Code": "12345",
"Name": "Hop Grower GmbH",
"City": "Mainburg",
"Country": "DE"
}
  1. Daten lokal speichern (MongoDB)

Die geladenen NAV-Daten werden zunächst in MongoDB gespeichert.

Beispiel:

await MSO.findOneAndUpdate(
{ businessCentralId: mso.Sales_Order_No },
{
businessCentralId: mso.Sales_Order_No,
data: mso,
company: dbCustomer?._id
},
{ new: true, upsert: true }
);

Damit existiert im Sync-Service eine lokale Kopie der NAV-Daten.

Diese Datenbank wird anschließend für den HubSpot-Sync verwendet.

Vorteile:

  • Wiederholbare Syncs
  • Batch-Verarbeitung
  • bessere Fehleranalyse
  • Entkopplung von NAV und HubSpot
  1. Daten transformieren

Im Controller wird das NAV-Format auf HubSpot-Format gemappt.

Beispiel:

NAV Feld                HubSpot Feld
---------------------------------------
Code → hop_company_number
Name → name
City → city
Country → country

4. Daten zu HubSpot senden

Danach werden die Daten über die HubSpot API gespeichert.

Typische API Calls:

POST /crm/v3/objects/companies/batch/upsert
POST /crm/v3/objects/contacts/batch/upsert
POST /crm/v3/objects/deals/batch/upsert

Beispiel Payload:

{
"inputs": [
{
"properties": {
"name": "Hop Grower GmbH",
"hop_company_number": "12345"
}
}
]
}

HubSpot speichert das dann in:

HubSpot ObjektDaten
CompaniesKunden / Grower
ContactsAnsprechpartner
DealsVerträge
Custom ObjectsMSO, SWS etc

5. Reihenfolge des Sync

Im Code steht ausdrücklich:

// Follow the API route sequence to maintain association in hubspot.

Warum? Weil HubSpot Relations braucht.

Die Reihenfolge ist:

1 Companies
2 SalesContracts
3 MSOs
4 PostedInvoices
5 SWS
6 SWSLines
7 MSOLines
8 PostedInvoiceLines

Beispiel Relation:

Company

└── Sales Contract

└── MSO

└── MSO Lines

Wenn du zuerst Lines importierst, existiert das Parent-Objekt noch nicht.

Full Sync Endpoint

Dieser Endpoint führt alle Syncs nacheinander aus.

routes.post(`/sync-all`, async (req, res) => {...})

Ablauf:

sync-all

├── handleCustomers()
├── handleSalesContracts()
├── handleMSOs()
├── handlePostedInvoices()
├── handleSWSs()
├── handleSWSLines()
├── handleMSOLines()
└── handlePostedInvoiceLines()

Das ist ein Full Import von NAV nach HubSpot.

6. HubSpot → NAV (Webhook)

Dieser Endpoint empfängt Änderungen aus HubSpot.

routes.post(`/webhook`, handleWebhook);

Beispiel: Wenn in HubSpot ein Contract geändert wird:

HubSpot

│ webhook

Express Service

│ NAV API

Business Central

Das System:

  1. empfängt den Webhook
  2. liest die Änderung
  3. sendet Update zurück an NAV

7. Datenquellen im System

Zusammenfassung.

SystemRolle
NAV / Business CentralMaster System
Express Sync ServiceIntegration Layer
HubSpotCRM

8. Gesamtfluss

Datenfluss NAV => HubSpot:

NAV (Business Central)

│ REST API

Express Sync Service

│ Mapping

HubSpot API


HubSpot CRM

Datenfluss HubSpot => NAV:

HubSpot

│ Webhook

Express Service


NAV API

9. Wichtig für dein Verständnis

Die Daten werden NICHT direkt von NAV nach HubSpot geschrieben.

Es gibt immer diesen Middleware Service:

NAV → Node Service (Express) → HubSpot

Der Vorteil:

  • Daten Mapping
  • Filter (z.B. Last_Date_Modified)
  • Fehlerhandling
  • Logging
  • Batch Upload

Kurzfassung:

SchrittBeschreibung
1Node API Endpoint wird aufgerufen
2Controller ruft NAV API auf
3NAV Daten werden geladen
4Daten werden gemappt
5Daten werden über HubSpot API gespeichert