Skip to content

feat: add source-dynamics-365-business-central manifest-only connector#74070

Draft
Ilja Herdt (Airbyte) (iherdt-airbyte) wants to merge 2 commits intomasterfrom
devin/1772137211-source-dynamics-365-business-central
Draft

feat: add source-dynamics-365-business-central manifest-only connector#74070
Ilja Herdt (Airbyte) (iherdt-airbyte) wants to merge 2 commits intomasterfrom
devin/1772137211-source-dynamics-365-business-central

Conversation

@iherdt-airbyte
Copy link
Contributor

@iherdt-airbyte Ilja Herdt (Airbyte) (iherdt-airbyte) commented Feb 26, 2026

What

Adds a new manifest-only (low-code) connector for Microsoft Dynamics 365 Business Central using the OData v4 REST API (v2.0).

Resolves #14405 (community request, revived for a customer).

How

Single manifest.yaml declarative connector with 8 streams:

Stream Sync Mode Cursor API Endpoint
companies Full Refresh GET /companies
general_ledger_entries Incremental lastModifiedDateTime GET /companies({id})/generalLedgerEntries
accounts Incremental lastModifiedDateTime GET /companies({id})/accounts
customers Incremental lastModifiedDateTime GET /companies({id})/customers
vendors Incremental lastModifiedDateTime GET /companies({id})/vendors
sales_invoices Incremental lastModifiedDateTime GET /companies({id})/salesInvoices
purchase_invoices Incremental lastModifiedDateTime GET /companies({id})/purchaseInvoices
journals Incremental lastModifiedDateTime GET /companies({id})/journals

Key design decisions:

  • Auth: OAuth 2.0 client credentials via Azure AD / Entra ID (same proven pattern as source-microsoft-entra-id)
  • Pagination: OData server-driven paging — extracts $skiptoken from @odata.nextLink (pattern from source-microsoft-entra-id)
  • Company scoping: SubstreamPartitionRouter with companies as parent stream; optional company_id config filters client-side via RecordFilter
  • Incremental: DatetimeBasedCursor with is_data_feed: true + server-side $filter=lastModifiedDateTime ge ... + $orderby=lastModifiedDateTime asc
  • Schemas: Inline, hand-crafted from MS API docs; all non-ID fields nullable; additionalProperties: true

Files added:

  • airbyte-integrations/connectors/source-dynamics-365-business-central/manifest.yaml — connector definition
  • airbyte-integrations/connectors/source-dynamics-365-business-central/metadata.yaml — registry metadata
  • airbyte-integrations/connectors/source-dynamics-365-business-central/icon.svg — connector icon
  • docs/integrations/sources/dynamics-365-business-central.md — user-facing documentation (setup guide, configuration, streams, changelog)

Review guide

Human review checklist — these are the areas most likely to contain issues since the connector has not been tested against a live Business Central instance:

  1. manifest.yaml — Incremental $filter logic (lines 60-61, 112-113, etc.):

    $filter: >-
      {{ 'lastModifiedDateTime ge ' ~ stream_interval.start_time if stream_interval else '' }}
    • Verify stream_interval.start_time is populated when is_data_feed: true (single slice mode)
    • Verify empty $filter= parameter doesn't break BC OData API (fallback when stream_interval is falsy)
  2. manifest.yaml$orderby support (lines 59, 111, etc.):

    • $orderby=lastModifiedDateTime asc — not all BC API endpoints may support $orderby on lastModifiedDateTime (not documented explicitly for every entity)
  3. manifest.yaml — OData pagination regex (lines 548-551):

    cursor_value: >-
      {{ response.get("@odata.nextLink", "") | regex_search('\$skiptoken=([^&]+)') }}
    • Verify BC's @odata.nextLink format matches this regex (borrowed from source-microsoft-entra-id / Microsoft Graph)
    • BC docs mention server-driven paging but don't show exact nextLink format
  4. manifest.yamlcompany_id filter (lines 35-37):

    condition: >-
      {{ config.get('company_id') is none or config.get('company_id') == '' or record['id'] == config['company_id'] }}
    • Verify client-side filtering logic handles empty string vs. null correctly
  5. metadata.yamldefinitionId (line 20):

    • definitionId: b5c21b91-1eab-46a3-ba01-910caaf3f567 — verify UUID doesn't collide with existing connector
  6. Schemas (lines 600-1375 in manifest.yaml):

    • All derived from MS docs, not live data — verify nullable types + additionalProperties: true provide sufficient defensive coverage
  7. Documentation (docs/integrations/sources/dynamics-365-business-central.md):

    • Verify setup instructions are clear and accurate
    • Verify stream table matches actual implementation

User Impact

Positive:

  • New connector enables syncing financial/GL data from Dynamics 365 Business Central
  • Manifest-only = low maintenance burden

Negative / Risks:

  • Untested against live API — may fail on first real use if:
    • OData pagination format differs from Microsoft Graph
    • $filter or $orderby parameters are rejected by BC API
    • stream_interval.start_time is not populated in is_data_feed: true mode
  • Alpha release stage — users should expect potential issues

Can this PR be safely reverted and rolled back?

  • YES 💚

New connector, no dependencies, OSS-only (cloud: enabled: false).


Link to Devin run: https://app.devin.ai/sessions/3cbb99948104440c8cb9722cd48d08c3
Requested by: Ilja Herdt (Airbyte) (@iherdt-airbyte)

Adds a new manifest-only (low-code) connector for Microsoft Dynamics 365
Business Central using the OData v4 REST API (v2.0).

Streams (8):
- companies (full refresh)
- general_ledger_entries (incremental)
- accounts (incremental)
- customers (incremental)
- vendors (incremental)
- sales_invoices (incremental)
- purchase_invoices (incremental)
- journals (incremental)

Features:
- OAuth 2.0 client credentials via Azure AD / Entra ID
- OData server-driven pagination (@odata.nextLink / $skiptoken)
- Company-scoped sub-streams via SubstreamPartitionRouter
- Server-side incremental filtering via OData $filter on lastModifiedDateTime
- Optional company_id config to scope sync to a single company

Resolves: #14405
Co-Authored-By: Ilja Herdt <ilja.herdt@airbyte.io>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@octavia-bot
Copy link
Contributor

octavia-bot bot commented Feb 26, 2026

Note

📝 PR Converted to Draft

More info...

Thank you for creating this PR. As a policy to protect our engineers' time, Airbyte requires all PRs to be created first in draft status. Your PR has been automatically converted to draft status in respect for this policy.

As soon as your PR is ready for formal review, you can proceed to convert the PR to "ready for review" status by clicking the "Ready for review" button at the bottom of the PR page.

To skip draft status in future PRs, please include [ready] in your PR title or add the skip-draft-status label when creating your PR.

@github-actions
Copy link
Contributor

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

PR Slash Commands

Airbyte Maintainers (that's you!) can execute the following slash commands on your PR:

  • 🛠️ Quick Fixes
    • /format-fix - Fixes most formatting issues.
    • /bump-version - Bumps connector versions, scraping changelog description from the PR title.
  • ❇️ AI Testing and Review (internal link: AI-SDLC Docs):
    • /ai-prove-fix - Runs prerelease readiness checks, including testing against customer connections.
    • /ai-canary-prerelease - Rolls out prerelease to 5-10 connections for canary testing.
    • /ai-review - AI-powered PR review for connector safety and quality gates.
  • 🚀 Connector Releases:
    • /publish-connectors-prerelease - Publishes pre-release connector builds (tagged as {version}-preview.{git-sha}) for all modified connectors in the PR.
    • /bump-progressive-rollout-version - Bumps connector version with an RC suffix (2.16.10-rc.1) for progressive rollouts (enableProgressiveRollout: true).
      • Example: /bump-progressive-rollout-version changelog="Add new feature for progressive rollout"
  • ☕️ JVM connectors:
    • /update-connector-cdk-version connector=<CONNECTOR_NAME> - Updates the specified connector to the latest CDK version.
      Example: /update-connector-cdk-version connector=destination-bigquery
    • /bump-bulk-cdk-version bump=patch changelog='foo' - Bump the Bulk CDK's version. bump can be major/minor/patch.
  • 🐍 Python connectors:
    • /poe connector source-example lock - Run the Poe lock task on the source-example connector, committing the results back to the branch.
    • /poe source example lock - Alias for /poe connector source-example lock.
    • /poe source example use-cdk-branch my/branch - Pin the source-example CDK reference to the branch name specified.
    • /poe source example use-cdk-latest - Update the source-example CDK dependency to the latest available version.
  • ⚙️ Admin commands:
    • /force-merge reason="<REASON>" - Force merges the PR using admin privileges, bypassing CI checks. Requires a reason.
      Example: /force-merge reason="CI is flaky, tests pass locally"
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

source-dynamics-365-business-central Connector Test Results

3 tests   1 ✅  3s ⏱️
1 suites  2 💤
1 files    0 ❌

Results for commit 63f945b.

♻️ This comment has been updated with latest results.

…central

Co-Authored-By: Ilja Herdt <ilja.herdt@airbyte.io>
@github-actions
Copy link
Contributor

Deploy preview for airbyte-docs ready!

✅ Preview
https://airbyte-docs-lbmzhqqz0-airbyte-growth.vercel.app

Built with commit 63f945b.
This pull request is being automatically deployed with vercel-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New Source: Microsoft Dynamics Business Central

2 participants