ml-connector
AcumaticaSlack

Acumatica and Slack integration

Acumatica runs finance, procurement, and distribution. Slack runs the conversations and approvals that surround those documents. Connecting the two means an AP bill, purchase order, or payment in Acumatica appears in the right Slack channel as a message with its key figures attached, and the approval that happens in Slack flows back to release or approve the document in Acumatica. ml-connector handles the very different APIs on each side and moves activity by webhook or on a schedule. Slack has no finance objects, so it stays the notification and approval layer while the records of account live in Acumatica.

How Acumatica works

Acumatica exposes vendors, AP bills, purchase orders, payments, GL accounts, journal transactions, customers, items, and employees through its Contract-Based REST API. The base URL is tenant-specific and the endpoint version in the path must exactly match the running ERP release, or the call returns a 404. Authentication is OAuth 2.0 through the built-in OpenID Connect server, or a legacy cookie session via /entity/auth/login. All field values are wrapped in value objects, and Acumatica can push record changes through Push Notifications (SM302000) using a shared-secret header rather than a signed payload, with polling on LastModifiedDateTime as the common fallback.

How Slack works

Slack exposes users, conversations, messages, files, and reactions through its Web API at slack.com/api, where every method is a family.action name called over HTTPS with a bearer bot token that begins with xoxb and does not expire. It has no native invoice, purchase order, payment, or GL account objects, so financial data is carried inside message text and Block Kit blocks rather than stored records. Slack pushes workspace activity through the Events API as signed HTTP POST callbacks that must be acknowledged within three seconds, and a simpler Incoming Webhook URL can post one-way notifications into a fixed channel.

What moves between them

The main flow runs from Acumatica into Slack. ml-connector reads new and changed bills, purchase orders, and payments and posts each one into a mapped Slack channel as a Block Kit message carrying the amount, vendor, due date, and reference number. Approval decisions flow back from Slack into Acumatica, where an Approve button click triggers the Release action on the matching bill and a reply can be recorded against the document. Slack has no chart of accounts or vendor master, so GL accounts and master data stay in Acumatica and are never written from Slack. Optionally, status changes such as a bill moving to Open or a payment clearing post follow-up updates into the same Slack thread.

How ml-connector handles it

ml-connector stores both credential sets encrypted, refreshes the Acumatica OAuth token when a call returns 401, and accepts the full tenant URL plus endpoint version per customer since Acumatica publishes no shared base address. On the Acumatica side it can receive Push Notifications through a shared-secret header or fall back to polling LastModifiedDateTime with $top and $skip offset pagination, because push delivery is not guaranteed and has no dead-letter queue. Each document is rendered as a Block Kit message with a plain text fallback and posted with chat.postMessage, which is capped at one message per second per channel, so the connector paces posts to stay under that limit. Inbound Slack events and interactive button clicks are verified by recomputing the HMAC-SHA256 signature from the signing secret and rejecting any request whose timestamp is older than five minutes, and the endpoint acknowledges within three seconds before doing the Acumatica work asynchronously. Because neither side offers an idempotency key, the connector dedupes Slack events on event_id and checks Acumatica for an existing record by natural key such as VendorRef before acting, and it stores the posted message ts so a re-read document updates the original message instead of posting a duplicate. Acumatica value-wrapped fields are unwrapped on read and rewrapped on write, both APIs return 429 with backoff so requests are retried, and every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A mid-sized distribution company with about 200 employees runs Acumatica for accounts payable, purchasing, and inventory, and runs Slack as its day-to-day communication tool across the warehouse and the office. Before the integration, approvers were emailed a spreadsheet of pending bills each morning, decisions came back hours later by reply, and someone in finance then re-keyed each approval into Acumatica to release the bill, which slowed payment runs and let some bills miss their discount dates. With Acumatica and Slack connected, every new bill over a set threshold posts into a finance channel with its amount and due date and an Approve or Reject button, and a click releases or holds the bill in Acumatica within seconds. The morning spreadsheet is gone, approvals happen where the team already works, and bills no longer stall waiting to be entered.

What you can do

  • Post new and changed Acumatica bills, purchase orders, and payments into mapped Slack channels as Block Kit messages.
  • Carry the amount, vendor, due date, and reference number from Acumatica into the Slack message and update the same thread on status changes.
  • Turn a Slack Approve or Reject button click into the matching Acumatica action, such as releasing a bill.
  • Verify every inbound Slack event and interaction by recomputing the signing-secret HMAC and rejecting stale or unsigned requests.
  • Bridge Acumatica OAuth or session login with a non-expiring Slack bot token, with retries and a full audit trail on every record.

Questions

How does the integration work when Slack has no invoice or purchase order objects?
Slack is a messaging platform with no finance records, so ml-connector represents each Acumatica bill, purchase order, or payment as a Slack message rather than a stored object. The figures, such as amount, vendor, and due date, are rendered into Block Kit blocks with a plain text fallback so notifications remain readable. The authoritative records stay in Acumatica, and Slack acts as the notification and approval layer on top of them.
Which direction does data move between Acumatica and Slack?
The main flow is Acumatica into Slack, where bills, purchase orders, payments, and their status changes are posted as channel messages. Approval decisions flow back from Slack into Acumatica, so an Approve button click can trigger the Release action on the matching bill. The Acumatica chart of accounts and vendor master stay in Acumatica and are never written from Slack.
How are inbound Slack requests verified and deduplicated?
Every Events API callback and interactive button click from Slack is verified by recomputing the HMAC-SHA256 signature from the signing secret over the timestamp and raw body, and any request older than five minutes or with a bad signature is rejected. The endpoint acknowledges within Slack's three-second window and then does the Acumatica work asynchronously. Because Slack retries on a non-2xx response, the connector deduplicates on the event_id in the payload so a retried delivery is not processed twice.

Related integrations

Connect Acumatica and Slack

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

Get started