ml-connector
QADBambooHR

QAD and BambooHR integration

QAD runs manufacturing and finance. BambooHR is the system of record for people: headcount, org structure, employment status, and compensation history. Connecting the two keeps the workforce in QAD in step with what HR maintains in BambooHR, so departments and cost centers used for GL tagging stay consistent and new hires, transfers, and terminations show up in QAD without manual re-entry. ml-connector handles the different APIs on each side and moves the data either on a schedule or in response to BambooHR change events. BambooHR holds no vendors, invoices, or GL accounts of its own, so the integration is shaped around employee and org data rather than finance documents.

How QAD works

QAD Adaptive ERP exposes suppliers, purchase orders, supplier invoices, GL accounts, cost centers, items, and goods receipts through REST business document APIs, documented in Swagger inside each customer instance. The cloud product authenticates with a JWT session or OAuth2 bearer token against a tenant-specific URL, so there is no shared hostname or public developer portal. Older on-premise sites run QAD Enterprise Edition with the QXtend SOAP framework instead. QAD cloud has no native webhook system for third-party connectors, so records are read by polling on a schedule.

How BambooHR works

BambooHR exposes employees, job information, compensation, employment status, time off, and benefits over a REST API at https://{companyDomain}.bamboohr.com/api/v1/, where the company subdomain is a required credential and is part of the auth URLs too. New apps authenticate with OAuth 2.0 authorization code, using the offline_access scope to obtain a refresh token for unattended sync; access tokens last one hour. A legacy API key over Basic auth still works for existing integrations. BambooHR signs webhooks with HMAC-SHA256 and pushes lightweight change events for employee created, updated, and deleted. Finance entities such as vendors, invoices, purchase orders, and GL accounts do not exist in BambooHR.

What moves between them

Data moves from BambooHR into QAD. ml-connector reads BambooHR employee records along with their department, division, location, and job title, and aligns QAD headcount and cost center dimensions with each change. Employment status drives hires, transfers, and terminations in QAD, and department to cost center mappings keep org data landing on valid QAD records. Because BambooHR has no finance documents, ml-connector does not move suppliers, invoices, or GL postings out of BambooHR; QAD remains the source for all finance data. Reference data such as departments and cost centers is reconciled so the two systems agree.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the BambooHR side it runs OAuth 2.0 authorization code against the customer subdomain, since the authorize and token URLs are subdomain-scoped rather than global, and it uses the offline_access refresh token to mint a new one-hour access token when a call returns 401. On the QAD side it accepts the full tenant URL per customer, since QAD publishes no shared base address, and validates entity paths against that instance. BambooHR webhooks are verified with a timing-safe HMAC-SHA256 check over the raw body plus the X-BambooHR-Timestamp header before anything is trusted; because the payload is intentionally lightweight, ml-connector then calls GET /api/v1/employees/{id} to fetch the current values. Where webhooks are not enabled, it polls the cursor-paginated employees endpoint on a schedule instead. Departments are mapped to QAD cost centers first, so every employee maps to an org dimension that already exists in QAD. BambooHR throttles with 503 and an optional Retry-After header, so ml-connector backs off and retries, and since BambooHR has no idempotency key it deduplicates on the BambooHR employee ID. Every record carries a full audit trail and can be replayed if a downstream QAD call fails.

A real-world example

A mid-sized contract manufacturer with around 400 employees runs QAD Adaptive ERP for production, procurement, and finance, and uses BambooHR as its HRIS across three sites. Before the integration, HR maintained departments, transfers, and terminations in BambooHR while a finance analyst re-keyed the same changes into QAD so labor cost centers and headcount stayed current, and the lists drifted apart between updates. With QAD and BambooHR connected, employee and org changes flow into QAD as they happen in BambooHR, mapped to the right cost center per site. Headcount and dimensions stay aligned without manual re-entry, and month-end allocations reference org data that matches HR.

What you can do

  • Sync BambooHR employees and their department, division, and job title into QAD as people are hired, moved, and terminated.
  • Map BambooHR departments to QAD cost centers so org data lands on valid QAD dimensions.
  • Verify BambooHR change webhooks with a timing-safe HMAC-SHA256 check, then fetch the current employee record from BambooHR.
  • Authenticate BambooHR with OAuth 2.0 on the company subdomain and a refresh token, and QAD with its tenant-specific token.
  • Poll or react to events on a schedule you control, with backoff on BambooHR throttling and a full audit trail on every record.

Questions

Which direction does data move between QAD and BambooHR?
Data moves from BambooHR into QAD. Employee records, departments, job titles, and employment status flow from BambooHR so QAD headcount and cost center dimensions stay current. BambooHR has no vendors, invoices, or GL accounts, so ml-connector does not pull finance data out of it; QAD remains the source for all finance records.
Does the integration use BambooHR webhooks or polling?
It can use either. BambooHR pushes lightweight change events for employee created, updated, and deleted, which ml-connector verifies with a timing-safe HMAC-SHA256 signature check and then follows with a GET on the employee to read the current values. Where webhooks are not enabled, it polls the cursor-paginated employees endpoint on a schedule you control.
How does ml-connector handle BambooHR OAuth and the per-customer subdomain?
BambooHR scopes both its base URL and its authorize and token URLs to each company subdomain, so ml-connector stores the subdomain as a credential and runs OAuth 2.0 authorization code against that instance. It requests the offline_access scope to obtain a refresh token and mints a fresh one-hour access token when a call returns 401. The legacy API key over Basic auth is also supported for existing integrations.

Related integrations

Connect QAD and BambooHR

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started