Skip to main content

D365 F&O Integration

How Konsolidat extracts data from Dynamics 365 Finance & Operations via Airbyte and OData.

Azure AD App Registration

Step-by-Step

  1. Go to Azure Portal → App Registrations
  2. Click New registration
    • Name: Konsolidat Airbyte
    • Supported account types: Single tenant
    • Redirect URI: Leave blank
  3. Note the Application (client) ID and Directory (tenant) ID
  4. Go to Certificates & secretsNew client secret
    • Description: Konsolidat production
    • Expiry: 24 months
    • Copy the secret value immediately (shown only once)
  5. Go to API permissionsAdd a permission
    • Select Dynamics ERP (Dynamics 365 Finance and Operations)
    • Choose Application permissions → check the access role (e.g. Connector.FullAccess / AX.FullAccess as exposed by your tenant)
    • Click Grant admin consent

The connector authenticates with the OAuth2 client-credentials flow (grant_type=client_credentials), so the app registration must be granted application permissions — there is no signed-in user. The token is requested from https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token with the scope {environment_url}/.default, which means the service principal must also be registered as an integrating application inside D365.

  1. In D365, go to System administration → Setup → Microsoft Entra ID applications (formerly Azure Active Directory applications) and register the Client ID with a user account that has the required data-access permissions. Without this step the token will be issued but OData calls return 401.

Required Values

ValueWhere to FindUsed By
Tenant IDApp registration → OverviewAirbyte source config
Client IDApp registration → OverviewAirbyte source config
Client SecretCertificates & secretsAirbyte source config
Environment URLD365 → System administrationAirbyte source config

The environment URL typically looks like: https://yourorg.operations.dynamics.com

OData Entities

The connector ships 14 D365 OData streams. All use cross-company=true by default to pull data across every legal entity in a single request (this can be disabled per-source via the cross_company setting).

General Ledger

The GL streams read the BI entity views (...BiEntities), which expose D365's internal SourceKey (RecId) as a monotonic surrogate primary key. Both sync incrementally on SourceKey.

OData EntityPurposePrimary Key / CursorKey Fields
GeneralJournalAccountEntryBiEntitiesGL line items (postings)SourceKey (incremental)SourceKey, GeneralJournalEntry, LedgerAccount, AccountingCurrencyAmount, IsCredit, PostingType, AccountingDate
GeneralJournalEntryBiEntitiesJournal headersSourceKey (incremental)SourceKey, JournalNumber, AccountingDate, DocumentNumber, PostingLayer, FiscalCalendarYear, FiscalCalendarPeriod

Chart of Accounts

OData EntityPurposePrimary KeyKey Fields
MainAccountsAccount masterMainAccountIdMainAccountId, Name, MainAccountType, MainAccountCategory, ChartOfAccounts
MainAccountCategoriesAccount category mappingReferenceIdReferenceId, MainAccountCategory, Description, MainAccountType

Organization

OData EntityPurposePrimary KeyKey Fields
LegalEntitiesCompany masterLegalEntityIdLegalEntityId, Name, PartyNumber, AddressCountryRegionId
LedgersLedger / currency configuration per legal entityLegalEntityIdLegalEntityId, AccountingCurrency, ReportingCurrency, Name, ChartOfAccountsId

Fiscal Calendar

OData EntityPurposePrimary KeyKey Fields
FiscalCalendarYearsFiscal year definitions(none)Calendar, FiscalYear, Description, StartDate, EndDate

Financial Dimensions

OData EntityPurposePrimary KeyKey Fields
DimensionAttributesDimension definitionsDimensionNameDimensionName, UseValuesFrom, ReportColumnName
FinancialDimensionValuesDimension value master(none)FinancialDimension, DimensionValue, Description, IsSuspended, ActiveFrom, ActiveTo

Exchange Rates

OData EntityPurposePrimary Key / CursorKey Fields
ExchangeRatesCurrency rate datacursor StartDate (incremental)FromCurrency, ToCurrency, StartDate, EndDate, Rate, ConversionFactor, RateTypeName
ExchangeRateTypesRate type definitionsNameName, Description

Budget

OData EntityPurposePrimary Key / CursorKey Fields
BudgetRegisterEntriesBudget register entriesEntryNumber, cursor Date (incremental)EntryNumber, BudgetModelId, BudgetCode, Status, Date, AccountingCurrencyAmount, DimensionDisplayValue

Consolidation

OData EntityPurposePrimary KeyKey Fields
ConsolidateAccountGroupsGroup mappingConsolidationAccountGroupConsolidationAccountGroup, ConsolidationAccountGroupName

Trial Balance Snapshot

OData EntityPurposePrimary KeyKey Fields
TrialBalanceFiscalYearSnapshotsPre-built TB snapshot(none)LedgerName, DimensionValue1, YearName, PeriodStartDate, OpeningBalance, AmountDebit, AmountCredit, EndingBalance

Airbyte Configuration

Source: Dynamics 365 Finance & Operations

SettingValue
Source typeDynamics 365 F&O (OData)
Tenant IDFrom Azure AD app registration
Client IDFrom Azure AD app registration
Client SecretFrom Azure AD app registration
Environment URLhttps://yourorg.operations.dynamics.com

Destination: ClickHouse

SettingValue
Hosthost.docker.internal (Docker) or ClickHouse hostname
Port8123
Databaseepm_bronze
Userdefault (or dedicated write user)
PasswordFrom .env

Stream Configuration

Enable all 14 streams listed above. For each stream:

  • Sync mode: Full Refresh (overwrite) for reference data; Incremental for the four streams that declare a cursor (GeneralJournalAccountEntryBiEntities and GeneralJournalEntryBiEntities on SourceKey, ExchangeRates on StartDate, BudgetRegisterEntries on Date)
  • Cursor field: as declared per stream above (not all streams support incremental)
  • Primary key: as declared per stream above — for example SourceKey for the GL BI entities, LegalEntityId for LegalEntities and Ledgers; several reference streams declare no primary key

Cross-Company Setting

By default all entity requests include cross-company=true in the OData query to retrieve data across all legal entities in the D365 instance. This is controlled by the cross_company source setting and can be disabled to restrict a sync to the service principal's default company.

Entity-to-Model Mapping

How D365 entities flow through the dbt layers:

OData Entity→ Bronze→ Silver→ Gold
GeneralJournalAccountEntryBiEntitiesbronze_general_journal_account_entry_bi_entitiessilver_gl_entriesgold_trial_balance
GeneralJournalEntryBiEntitiesbronze_general_journal_entry_bi_entitiessilver_gl_entries (joined)
MainAccountsbronze_main_accountssilver_main_accounts
MainAccountCategoriesbronze_main_account_categoriessilver_main_accounts (joined)
LegalEntitiesbronze_legal_entitiessilver_legal_entities
Ledgersbronze_ledgerssilver_legal_entities (joined)
FiscalCalendarYearsbronze_fiscal_calendar_yearssilver_fiscal_periodsgold_period_hierarchy
ExchangeRatesbronze_exchange_ratessilver_exchange_ratesgold_consolidated_trial_balance
BudgetRegisterEntriesbronze_budget_register_entriessilver_budget_entriesgold_spread_budget

Sync Schedule

ApproachFrequencyBest For
Manual (via task pane or API)On-demandDevelopment, ad-hoc
Airbyte schedulerDaily at off-peak hoursStandard production
Event-drivenOn D365 postingReal-time requirements

Troubleshooting

IssueCauseFix
401 Unauthorized from D365Expired client secret, or the service principal is not registered in System administration → Setup → Microsoft Entra ID applicationsRotate the secret; verify the Client ID is registered as an integrating app with a permitted access role in D365
Empty sync resultscross-company disabled (only the default company is returned)Re-enable the cross_company source setting
Missing entitiesEntity not enabled in D365Contact D365 admin to expose the data entity
Timeout on large syncsToo many records in one batchIncrease Airbyte timeout, use incremental sync
Rate limiting (429)D365 throttlingReduce batch size, add retry logic

Next Steps