Hyppää sisältöön

DocEx — Document Exchange for Business Central

DocEx is a framework by Fellowmind Finland that simplifies integrating Microsoft Dynamics 365 Business Central with external systems through file and message exchange. Rather than building file transfer logic from scratch for each integration project, DocEx provides a ready-made, extensible platform for sending and receiving files via cloud storage solutions and protocols such as Azure Blob Storage, Azure File Share.

Using DocEx cuts down integration implementation costs and provides an easy-to-use, standardized framework for handling file transfers. Custom message handling (e.g. XML, CSV, EDI) can then be built on top of the file transfer layer.


Table of Contents


App Suite Overview

DocEx is distributed as a suite of AppSource apps. Install the core app plus whichever connectors are needed for your integration scenario.

App Purpose
DocEx (Core) Platform for exchanging messages to/from Business Central. Required by all connectors.
DocEx File Connector Manual file import/export via browser download and upload dialogs.
DocEx Azure Blob V2 Connector Automated file exchange with Azure Blob Storage containers.
DocEx Azure Fileshare V2 Connector Automated file exchange with Azure File Shares.
DocEx Migration One-time PTE migration tool for upgrading from the old PTE version to AppSource. See Migration Guide.

All apps are published by Fellowmind Finland and target Business Central platform 24.0 and later.


Architecture

DocEx uses a three-tier architecture for message exchange:

flowchart LR
    subgraph External["External Systems"]
        Blob["Azure Blob Storage"]
        AFS["Azure File Share"]
        File["Local Files"]
    end

    subgraph DocEx["DocEx in Business Central"]
        GW["Gateway\n(Inbound / Outbound)"]
        MC["Message Channel\n(Inbox / Outbox Queue)"]
        DOC["Documents\n(Header + Lines + Aux. Data)"]
    end

    External <-->|Connector| GW
    GW <--> MC
    MC <--> DOC

Key Entities

Entity Description
Gateway A named connection endpoint. Each gateway is either Inbound (receive) or Outbound (send), and is linked to a specific connector (e.g. Azure Blob, Azure File Share).
Message A file payload container identified by a GUID. Holds the file content as a blob, along with filename and length.
Message Channel A queue entry linking a message to a gateway. Tracks the processing status of each message (Open → Queued → Processing → Processed / Failed).
Document An optional EDI/business document representation with typed header, lines, and auxiliary data. Used for structured document processing on top of raw file exchange.
Document Line Line items within a document (items, G/L accounts, resources, etc.).
Auxiliary Data Flexible key-value storage attached to documents. Supports text, blob, integer, and decimal values for custom fields.

Getting Started

1. Install the Apps

Install DocEx (the core app) from AppSource, then install the connector app(s) you need. Each connector app depends on the core app.

2. Configure DocEx Setup

Open the DocEx Setup page to configure:

  • License — License key and expiration
  • Document Number Series — Start/end numbers for inbound and outbound documents
  • Custom Document Processing Codeunits — Optional codeunit IDs for processing documents (general, inbound-specific, outbound-specific)

3. Assign Permissions

Assign the DocEx Module permission set to users who need access to DocEx. Each connector app provides its own permission set extension that is automatically included.

4. Set Up Connector Accounts

Configure storage accounts or server connections for each connector you installed (see Connectors below).

5. Create Gateways

Create one or more gateways for your integration points (see Gateway Configuration).


Connectors

File Connector

The File Connector enables manual import and export of files through the browser.

  • Send (Outbound): Downloads the file to the user's computer via the browser download dialog.
  • Receive (Inbound): Prompts the user to select a file via the browser upload dialog.

Configuration: No account or settings configuration is needed — the connector is stateless.

Note: The File Connector cannot run in the background (Job Queue). It requires an active user session.


Azure Blob Storage Connector

Exchanges files with Azure Blob Storage containers. Supports automated background processing.

Blob Account Setup

Navigate to the Azure Blob Storage account settings and configure:

Field Description
Account Name Azure Storage account name
Container Name Blob container name
Access Key Storage account access key (stored securely in Isolated Storage)

The Container URL is generated automatically as https://<account>.blob.core.windows.net.

Use the Test Connection action to verify your configuration.

Blob Gateway Settings

Field Description
Prefix Folder prefix for filtering files (e.g. outbound/invoices/)
File Mask Pattern for matching filenames
Use Regex Enable regex pattern matching for the file mask
Action on Import Do Nothing / Archive (Copy) / Delete — what to do with the source file after receiving
Archive Container Name Target container for archived files (when using Archive action)
Archive Folder Name Target folder path within the archive container

Azure File Share Connector

Exchanges files with Azure File Shares. Supports automated background processing.

File Share Account Setup

Field Description
Account Name Azure Storage account name
Fileshare Name Azure File Share name
Authentication Type Access Key or SAS Token
Access Key Storage account access key (when using Access Key auth)
SAS Token Shared Access Signature token (when using SAS Token auth)

When using SAS Token authentication:

  • The SAS Token Expiration date is automatically parsed from the token.
  • A warning is displayed if the token expires within 7 days.
  • An error is shown if the token has already expired.

The Fileshare URL is generated automatically as https://<account>.file.core.windows.net.

File Share Gateway Settings

Field Description
Prefix Folder prefix for filtering files
Action on Import Do Nothing / Archive (Copy) / Delete
Archive Fileshare Name Target file share for archived files
Archive Folder Name Target folder path within the archive share

File Share Browser

The Azure File Share connector includes a built-in File Browser page where you can:

  • Browse files and folders in the file share
  • Upload, download, and delete files manually
  • View file metadata (size, dates, attributes)

Gateway Configuration

A Gateway is a named integration endpoint that is either Inbound (receiving files) or Outbound (sending files).

Creating a Gateway

  1. Open the DocEx Gateways page.
  2. Create a new gateway and fill in:
Field Description
Gateway Code Unique identifier for the gateway (e.g. ACME.IN.ORDERS)
Direction Inbound or Outbound
Description Human-readable description
Gateway Connector Select the connector type (File, Azure Blob, Azure File Share)
Processing Object Type Codeunit or XMLport — the object to run when processing messages
Processing Object ID The ID of the processing codeunit or XMLport
Default Filename Template Template for generating filenames on outbound messages (see Filename Templates)
Auto Enqueue On Creation Automatically enqueue outbound messages for sending when they are created
Allow Job Queue Allow this gateway to be used from Job Queue automation

Naming Conventions

Use a naming convention that makes it easy to identify the integration partner, direction, and message type. A recommended pattern:

<PARTNER>.<DIRECTION>.<MESSAGE_TYPE>

Examples:

Gateway Code Description
ACME.IN.ORDERS Inbound orders from Acme Group
ACME.OUT.INVOICES Outbound invoices to Acme Group
DXL.OUT.PICKREQUEST Outbound pick requests to DXL Logistics
DXL.IN.PICKCONFIRM Inbound pick confirmations from DXL Logistics

A consistent naming convention also enables effective filtering in Job Queue automation (e.g. SEND[ACME*]).

Connector Configuration

After selecting a connector, use the Configure action on the gateway to open the connector-specific settings page. This is where you link the gateway to a storage account and configure file paths, masks, and import actions (see Connectors for details per connector type).


Message Flow

Outbound (Sending)

flowchart LR
    A["Create Message"] --> B["Message Channel\n(Status: Open)"]
    B --> C["Enqueue\n(Status: Queued)"]
    C --> D["Send via Connector\n(Status: Processing)"]
    D --> E["Archive\n(Status: Processed)"]
    D --> F["Error\n(Status: Failed)"]
  1. A message is created (programmatically or via XMLport export) and linked to an outbound gateway.
  2. The message appears in the Message Channel with status Open.
  3. Enqueuing marks the message as Queued (this can happen automatically if "Auto Enqueue On Creation" is enabled).
  4. The channel dispatcher calls the connector's Send method to transfer the file.
  5. On success, the message is moved to the archive. On failure, it is marked Failed.

Inbound (Receiving)

flowchart LR
    A["Connector Receives Files"] --> B["Message Channel\n(Status: Open)"]
    B --> C["Process Message\n(Status: Processing)"]
    C --> D["Archive\n(Status: Processed)"]
    C --> E["Error\n(Status: Failed)"]
  1. The connector's Receive method pulls files from the external storage.
  2. Each file becomes a message in the Message Channel with status Open.
  3. Processing runs the gateway's configured codeunit/XMLport on the message content.
  4. On success, the message is archived. On failure, it is marked Failed or Failed (Retry).

Message Statuses

Status Description
(blank) New / uninitialized message
Queued Waiting to be sent or processed
Processing Currently being sent or processed
Processed Successfully completed
Failed An error occurred during processing
Failed (Retry) An error occurred; queued for automatic retry

Manual Operations

From the DocEx Gateways page, you can manually trigger:

  • Receive — Pull files from the connector for inbound gateways
  • Send — Enqueue and send all open messages for outbound gateways
  • Process — Process all open messages in the channel
  • Receive & Process — Receive and immediately process (inbound only)
  • Process & Send — Process outbound data and send

Document Processing

Documents provide a structured, typed layer on top of raw message exchange. They are useful for EDI-style integrations where messages represent business documents.

Document Types

DocEx includes 26 built-in document types (the enum is extensible — see Extending Document Types):

Type Type Type
Quote Order Invoice
Credit Memo Blanket Order Return Order
Shipment Receipt Order Response
Order Change Instructions to Despatch Invoice List
JIT Delivery Consignment Package
Packaging (Position) Inventory Report Sales Report
Catalog Warehouse Instruction Warehouse Notification
Delivery Note Proforma Invoice Goods Received Note
Goods Dispatched Note Transfer Order

Document Lifecycle

stateDiagram-v2
    [*] --> Open
    Open --> Released
    Open --> Processed
    Open --> Error
    Released --> Open : ReOpen
    Error --> Open : ReOpen
    Open --> Rejected
  • Open — The document is ready for processing
  • Released — The document has been manually released
  • Processed — Processing completed successfully
  • Error — An error occurred during processing (the error text is stored in the Status String field)
  • Rejected — The document was manually rejected

Projects and Message Types

For more complex integrations, organize your gateways using Project Codes and Message Types.

Example — Warehouse Integration with DXL Logistics:

Concept Value Description
Project Code DXL DXL Logistics
Message Type PICK_REQUEST Outbound picking request
Message Type PICK_CONFIRM Inbound pick confirmation
Gateway DXL.OUT.PICKREQUEST Sends pick requests
Gateway DXL.IN.PICKCONFIRM Receives confirmations

Document Automation

The DocEx Document Automation page lets you configure automatic background processing of documents by document type and direction:

Field Description
Document Type The document type to automate
Direction Inbound or Outbound
Allow JQ Enable Job Queue processing
Last Run Timestamp of the last automation run
Last Processed Run Timestamp of the last run that found documents to process

Use the DOC_PROCESS Job Queue parameter to trigger document automation (see Job Queue Automation).


Job Queue Automation

DocEx gateways and document processing can be fully automated using Business Central's Job Queue.

Setup

  1. Create a new Job Queue Entry.
  2. Set the Object Type to Run to Codeunit.
  3. Set the Object ID to Run to 72310605 (DocEx Job Handler).
  4. Set the Parameter String to one of the actions below.

Actions

Parameter String Description
RECEIVE Receive files for all inbound gateways with "Allow Job Queue" enabled
SEND Enqueue and send all open messages for outbound gateways with "Allow Job Queue" enabled
PROCESS Process all open messages for all gateways with "Allow Job Queue" enabled
DOC_PROCESS Process open documents using Document Automation rules

Gateway Filtering

Add a filter inside square brackets [ ] after the action to target specific gateways:

Example Effect
RECEIVE[*IN*] Receive for all gateways with "IN" in the Gateway Code
SEND[ACME*] Send for all gateways starting with "ACME"
PROCESS[DXL.*] Process for all gateways starting with "DXL."
RECEIVE[ACME.IN.ORDERS] Receive for one specific gateway

Prerequisites

  • The gateway must have Allow Job Queue enabled. This is a safety measure — newly created gateways will not be picked up by existing Job Queue entries until explicitly enabled.
  • An error is raised if the filter matches no active gateways, alerting the user to review the Job Queue Entry settings.

Business Events

DocEx publishes Business Events that allow external systems (e.g. Power Automate) to react to activity in Business Central.

DocEx Document Error on Process

Triggered when a document processing operation results in an error.

Event Parameters:

Parameter Type Example
Direction Text[10] Inbound
DocumentType Enum Order
DocumentNo Code[20] 100000
SystemId Guid 165b0689-458b-4f3a-88e2-7c09313ca780
LastErrorCode Text[250] Error code
LastErrorText Text[250] An error occurred. The last error description

Example: Power Automate Flow

Use this business event to create a Power Automate flow that sends email or Teams notifications when a document fails processing. Configure the flow to trigger on the DocExDocumentError business event, then use the parameters to build a meaningful alert message.


API Integration

DocEx exposes API v1 pages for OData-based integration with external systems:

  • DocEx Documents API — Read and manage document headers
  • DocEx Document Lines API — Read and manage document lines
  • DocEx Auxiliary Data API — Read and manage auxiliary key-value data

These APIs are published as standard Business Central API pages with:

  • Publisher: fellowmind
  • API Group: docex
  • Version: v1.0

Available API Entities

API Entity Name Entity Set Name Purpose
DocEx Documents document documents Document headers and main document metadata
DocEx Document Lines documentLine documentLines Lines belonging to DocEx documents
DocEx Auxiliary Data auxData auxDatas Flexible key-value data for documents and document lines

Endpoint Structure

The APIs follow the standard Business Central API route pattern:

/api/fellowmind/docex/v1.0/companies({companyId})/documents
/api/fellowmind/docex/v1.0/companies({companyId})/documentLines
/api/fellowmind/docex/v1.0/companies({companyId})/auxDatas

Typical use cases include:

  • creating DocEx documents from an external integration service
  • reading document headers and lines for downstream processing
  • storing and retrieving custom integration metadata through auxiliary data

These API pages enable external systems to query, create, and update DocEx documents programmatically via standard Business Central OData/REST APIs.


Developer Guide

This section is for AL developers building integrations on top of DocEx or extending its functionality.

Creating a Custom Connector

To add a new connector (e.g. for a different cloud storage, API, or protocol), you need three components:

1. Enum Extension

Extend the DocEx Gateway Connector enum with your connector value:

enumextension 50100 "My Custom Connector" extends "DocEx Gateway Connector FMD"
{
    value(50100; "My Custom Connector")
    {
        Caption = 'My Custom Connector';
        Implementation =
            "DocExIfaceGatewayConnector FMD" = "My Connector Codeunit";
    }
}

2. Interface Implementation

Create a codeunit that implements the DocExIfaceGatewayConnector interface:

codeunit 50100 "My Connector Codeunit"
    implements "DocExIfaceGatewayConnector FMD"
{
    procedure Send(GatewayId: Guid)
    begin
        // Send all queued messages for this gateway
    end;

    procedure Send(DocExMessage: Codeunit "DocEx Message FMD"; GatewayId: Guid)
    begin
        // Send a specific message
        // Use DocExMessage.Message_GetContent(Stream) to get the file content
        // Use DocExMessage.GetName() to get the filename
    end;

    procedure Receive(GatewayId: Guid)
    begin
        // Pull files from external system
        // For each file, create a message:
        //   DocExMessage.Create(GatewayCode, InStream, FileName);
    end;

    procedure Configure(GatewayId: Guid)
    begin
        // Open your connector's settings page for this gateway
    end;

    procedure DeleteGateway(GatewayId: Guid)
    begin
        // Clean up connector settings when a gateway is deleted
    end;

    procedure GetConnectorDescription(): Text[250]
    begin
        exit('My Custom Connector - description');
    end;

    procedure GetConnectorid(): Guid
    begin
        exit('00000000-0000-0000-0000-000000000000'); // Your unique connector GUID
    end;
}

3. Supporting Tables and Pages (Optional)

If your connector needs configuration (accounts, paths, credentials), create:

  • An Accounts table for storing connection credentials (use IsolatedStorage for secrets)
  • A Settings table for per-gateway configuration (prefix, file masks, import actions)
  • Configuration pages for managing accounts and settings

Follow the pattern used by the built-in connectors (e.g. DocEx AzureBlob V2 Accounts, DocEx Azure Blob V2 Settings).


Extending Document Types

The DocEx Document Type enum is extensible. Add custom document types for your integration:

enumextension 50100 "My Document Types" extends "DocEx Document Type FMD"
{
    value(50100; "Custom Type")
    {
        Caption = 'Custom Type';
    }
}

Custom Document Processing

There are two approaches for custom document processing logic:

Subscribe to the DocExDocumentManagementOnProcess event in codeunit DocEx Document Management:

[EventSubscriber(ObjectType::Codeunit, Codeunit::"DocEx Document Management FMD",
    'DocExDocumentManagementOnProcess', '', false, false)]
local procedure OnDocExDocumentProcess(var DocExDocument: Record "DocEx Header FMD"; var Handled: Boolean)
begin
    // Your processing logic here
    // Set Handled := true when you've processed the document
    Handled := true;
end;

When Handled is set to true, the document status is automatically set to Processed.

Option 2: Setup Codeunits

Register custom processing codeunit IDs in the DocEx Setup page:

Field Scope
Custom Doc. Processing ID Runs for all documents (fallback)
Custom In Doc. Processing ID Runs for inbound documents only
Custom Out Doc. Processing ID Runs for outbound documents only

The processing order is:

  1. Integration event (DocExDocumentManagementOnProcess)
  2. Direction-specific codeunit (if configured)
  3. General codeunit (if no direction-specific codeunit is configured)

Creating Messages Programmatically

Use the DocEx Message codeunit to create and manage messages:

var
    DocExMessage: Codeunit "DocEx Message FMD";
    TempBlob: Codeunit "Temp Blob";
    OutStream: OutStream;
    InStream: InStream;
begin
    // Build your file content
    TempBlob.CreateOutStream(OutStream, TextEncoding::UTF8);
    OutStream.WriteText('Your file content here');
    TempBlob.CreateInStream(InStream);

    // Create the message and send to a gateway
    DocExMessage.Create('ACME.OUT.INVOICES', InStream, 'invoice_001.xml');
end;

Public API Methods

Method Description
Create(GatewayCode, DataStream) Create a message with auto-generated filename
Create(GatewayCode, DataStream, FileName) Create a message with a specific filename
Create(GatewayId, DataStream) Create a message using gateway GUID
Create(GatewayId, DataStream, FileName) Create a message using gateway GUID with specific filename
Get(MessageId): Boolean Retrieve a message by its GUID
GetName(): Text[2048] Get the filename of the current message
Message_GetContent(var InStream) Get the file content as a stream
Message_GetContentBase64(): Text Get the file content as Base64-encoded text
Message_GetLength(): Integer Get the content length in bytes

Empty data streams are silently ignored (no message is created).


Filename Templates

Gateways can define a Default Filename Template for auto-generating filenames on outbound messages. The following placeholders are supported:

Placeholder Description Example
{Timestamp[format]} Current date/time in the specified format {Timestamp[yyyyMMdd_HHmmss]}20260511_143022
{Guid} A new unique identifier a1b2c3d4-e5f6-...
{Code} The gateway code ACME.OUT.INVOICES

Example template: INV_{Timestamp[yyyyMMdd_HHmmss]}_{Guid}.xml

If no template is specified on the gateway, the system falls back to the global setup.


Auxiliary Data

The Document Auxiliary Data table provides flexible key-value storage for attaching custom data to documents without modifying the core tables.

Each entry supports multiple value types simultaneously:

Field Type Use Case
Value Text[250] Short text values
Value Blob Blob Large text or binary data
Value Int Integer Numeric identifiers or counts
Value Decimal Decimal Amounts or quantities

Auxiliary data entries are linked to a document by Document Type, Document No., and optionally Document Line No. for line-level data.


Further Reading