ml-connector
QADMicrosoft Teams

QAD and Microsoft Teams integration

QAD runs manufacturing and finance, and Microsoft Teams is where the people who approve that work already talk. Connecting the two turns QAD finance events into notifications and approval requests inside Teams, so a purchase order approved or a supplier invoice received shows up in the right channel without anyone watching the ERP. Microsoft Teams has no invoice, purchase order, or GL objects of its own, so this connection treats it as a notification and approval surface, not a second system of record. ml-connector reads the events from QAD, formats them as Teams messages, and listens for replies through Microsoft Graph. It handles the very different login on each side and runs on a schedule you control.

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 sandbox. Older on-premise sites run QAD Enterprise Edition with the QXtend SOAP framework, where QXO can push XML events. QAD cloud has no native webhook system for connectors, so finance records are read by polling on a schedule.

How Microsoft Teams works

Microsoft Teams has no standalone API; all access goes through the Microsoft Graph REST API at https://graph.microsoft.com/v1.0/, returning JSON with OData paging. A server connector uses OAuth2 client credentials, which means a registered Microsoft Entra ID app, a client secret, and admin-consented application permissions scoped to a tenant ID. The relevant entities are teams, channels, channel and chat messages, and users, since Teams has no invoice, purchase order, GL, or vendor objects. Microsoft Teams supports real push notifications through Graph change notification subscriptions, validated by a clientState value rather than an HMAC header, with a maximum subscription lifetime of about three days.

What moves between them

The main flow runs from QAD into Microsoft Teams. ml-connector reads QAD finance events such as purchase order approvals, supplier invoices received, goods receipts posted, and payments released, then posts each one into the chosen Teams channel as an adaptive card or plain message. Because QAD has no invoice, PO, or GL objects on the Teams side to write into, nothing financial flows back into QAD from Teams as a record. What does come back is human activity: through Graph change notification subscriptions, ml-connector receives channel message replies and approval responses and uses them to advance the matching QAD flow. QAD users can also be matched to Teams users so messages mention or direct-message the right reviewer.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the QAD side it accepts the full tenant URL per customer, since QAD publishes no shared base address, and polls QAD business document APIs for new finance events because QAD cloud is pull-only. On the Teams side it requests a Microsoft Graph token with the client credentials flow and the https://graph.microsoft.com/.default scope, which requires the Entra ID app to be admin-consented first; non-admin users cannot grant those permissions. Each QAD event maps to a Teams channel message, formatted as an adaptive card when the flow needs an approval button. To receive replies it creates a Graph subscription on the target channel messages and verifies the validationToken handshake and the clientState on every notification, since Graph sends no HMAC signature. Teams subscriptions expire in about three days, so ml-connector renews them and handles lifecycle notifications before they lapse. Graph throttling returns HTTP 429 with a Retry-After header, which ml-connector honors with backoff, and because Graph has no idempotency key, each post is deduplicated with a BullMQ jobId so a retry never doubles a message. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A mid-sized contract manufacturer runs QAD Adaptive ERP for procurement and accounts payable and runs the rest of the company in Microsoft Teams. Before the integration, buyers and plant managers had to keep a QAD tab open to catch purchase orders waiting on approval and supplier invoices stuck in three-way match, and approvals slipped because nobody saw them in time. With QAD and Microsoft Teams connected, each of those events lands in a procurement channel as an adaptive card the moment it fires in QAD, the approver acts from inside Teams, and the reply flows back to advance the QAD flow. Approvals that used to wait a day now clear in minutes, and the people doing the approving never have to leave the tool they live in.

What you can do

  • Post QAD finance events such as PO approvals and supplier invoices received into the right Microsoft Teams channel as adaptive cards or messages.
  • Receive approval replies and channel activity back from Teams through Microsoft Graph change notification subscriptions.
  • Authenticate Teams with OAuth2 client credentials and an admin-consented Entra ID app, and QAD with its tenant-specific token.
  • Renew the short three-day Graph subscriptions automatically and verify each notification by its clientState.
  • Deduplicate every message with a BullMQ jobId and back off on Graph 429 throttling, with a full audit trail on each record.

Questions

Can Microsoft Teams hold QAD invoices, purchase orders, or GL data?
No. Microsoft Teams has no invoice, purchase order, GL, or vendor objects, and it is reached only through the Microsoft Graph API as a chat and collaboration surface. ml-connector uses it as a notification and approval channel, posting QAD finance events as Teams messages rather than storing any financial records there. QAD stays the single system of record.
How does ml-connector know when someone approves in Microsoft Teams?
ml-connector registers a Microsoft Graph change notification subscription on the target channel, so Teams pushes replies and approval responses to the connector instead of it polling. Graph does not use an HMAC signature, so each notification is verified by matching the clientState value set at subscription time. Because these subscriptions last about three days, ml-connector renews them and handles lifecycle notifications so the pushes keep arriving.
What setup does the Microsoft Teams side need before the connection works?
An Azure AD global admin must register an app in Microsoft Entra, create a client secret, and consent to the application permissions the connector needs, since app-only Graph permissions cannot be granted by a regular user. The customer then provides the tenant ID, client ID, and client secret, which ml-connector stores encrypted. On the QAD side, the customer's tenant-specific instance URL is configured because QAD publishes no shared base address.

Related integrations

Connect QAD and Microsoft Teams

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

Get started