Skip to main content

Python SDK and CLI for Microsoft Dynamics 365 Business Central APIs

Project description

bcli

PyPI Tests License: Apache 2.0 Python

A Python SDK and CLI for Microsoft Dynamics 365 Business Central APIs, with a built-in dlt source for ETL backup pipelines.

Status: Alpha (0.1.x). Public surface may change before 1.0. Track CHANGELOG.md for breaking changes. Independent project by @igor-ctrl — not affiliated with Microsoft.

SDK Quick Start

from bcli import AsyncBCClient

# Programmatic auth — no config files needed
async with AsyncBCClient(
    tenant_id="your-tenant-id",
    client_id="your-app-id",
    client_secret="your-secret",
    environment="Sandbox",
    company_id="your-company-id",
) as client:
    # Query with fluent OData builder
    customers = await client.query("customers").filter("city eq 'Chicago'").top(10).get()

    # Write with safety gate
    async with client.safe_write("Sandbox", "your-company-id") as sw:
        await sw.post("salesInvoices", body={"customerNumber": "10000"}, domain="finance")

Or use TOML profiles for the CLI and repeated SDK use:

from bcli import AsyncBCClient

async with AsyncBCClient(profile="production") as client:
    vendors = await client.query("vendors").select("displayName", "balance").get()

CLI Quick Start

# Install (PyPI distribution name is "bc-cli"; the binary is "bcli")
pip install bc-cli
# or
uv tool install bc-cli

# Configure (interactive — discovers companies automatically)
bcli config init

# Query standard APIs immediately
bcli get customers --top 5
bcli get vendors --filter "displayName eq 'Fabrikam'" --format json
bcli get salesInvoices --select number,totalAmountIncludingTax --top 10

# Import custom APIs from a Postman collection
bcli registry import --from-postman ./my_collection.json

# Query custom endpoints (route auto-resolved)
bcli get myCustomEntities --top 5

Features

  • Works out of the box — 79 standard BC v2.0 entities (customers, vendors, items, GL entries, ...) with zero configuration beyond auth
  • Custom API support — Import your custom API pages from Postman collections, JSON, or live $metadata
  • Three-tier endpoint resolution — Custom registry -> standard v2.0 -> fuzzy suggestions
  • Multi-company — Assign aliases to companies and query across all entities
  • OData query builder--filter, --select, --expand, --orderby, --top, --skip on every query
  • Multiple output formats — table, JSON, CSV, NDJSON for pipeline use
  • Secure auth — OS keychain integration (macOS Keychain, Windows Credential Manager), token caching, client credentials + device code flows
  • Write safety — SafeContext gate prevents wrong-environment writes, enforces draft status on financial documents
  • Programmatic auth — Pass credentials directly for MCP servers, Airflow DAGs, and containers (no config files required)
  • Batch operations — Execute sequences of API calls from YAML files
  • ETL pipeline — Built-in dlt source for incremental backup to Parquet / DuckDB / Iceberg / Postgres
  • Structured logging — JSON request logs with correlation IDs for observability

ETL Pipeline (dlt source)

Sync BC data incrementally to any dlt-supported destination — useful as a Fivetran backup, a warehouse backfill tool, or a standalone ETL runner.

Standalone (any BC tenant, no bcli config required):

import dlt
from bcli.etl import business_central, EntityDef, fivetran_stamper

source = business_central(
    tenant_id="...", client_id="...", client_secret="...",
    environment="Production",
    entities=[
        EntityDef(name="customers"),
        EntityDef(name="vendors"),
    ],
    multi_company=True,             # iterate all BC companies
    stampers=[fivetran_stamper()],  # add _fivetran_synced / _fivetran_deleted
)

pipeline = dlt.pipeline(destination="duckdb", dataset_name="bc_raw")
pipeline.run(source)

Or use the bcli bridge (reuses your profile and custom-API registry):

# List entities the pipeline will sync
bcli --profile prod etl entities

# Incremental sync (uses systemModifiedAt cursor)
bcli --profile prod etl sync --destination filesystem

# Full refresh
bcli --profile prod etl sync --destination filesystem --full-refresh

# Schedule via cron (every 10 min incremental, nightly full refresh)
*/10 * * * * bcli --profile prod etl sync --destination filesystem
0 0 * * *    bcli --profile prod etl sync --destination filesystem --full-refresh

Installation

Requires Python 3.11+.

Heads-up on the package name. The PyPI name is bc-cli, not bcli. An unrelated 2018-era package squats on the bcli name (an "EC2 Cluster Creator" with no relation to this project) — pip install bcli will install that, not this. Always pip install bc-cli. Once installed, the import name (import bcli) and the CLI binary (bcli) work as documented.

# SDK only (for libraries, MCP servers, Airflow DAGs)
pip install bc-cli

# SDK + CLI
pip install "bc-cli[cli]"

# SDK + ETL (dlt source for backup pipelines)
pip install "bc-cli[etl]"

# Everything
pip install "bc-cli[cli,etl]"

# Via uv (recommended)
uv tool install bc-cli

# From source
git clone https://github.com/igor-ctrl/bcli.git
cd bcli
pip install -e ".[dev,etl]"

Documentation

Guide Description
Getting Started First-time setup, authentication, your first query
Configuration Profiles, environments, config file format
Authentication Client credentials, device code, OS keychain
Querying Data GET, OData filters, pagination, output formats
Write Operations POST, PATCH, DELETE
Custom APIs Importing from Postman, JSON, or $metadata
Multi-Company Company aliases, cross-entity queries
Batch Operations YAML batch files
SDK Usage Python SDK for developers and MCP servers
MCP Server Drive bcli from Claude Desktop via the bcli-mcp server (preview)
Command Reference Complete CLI command reference
For AI Agents Quick discovery recipes for Claude Code, Cursor, etc. driving bcli on a user's behalf
Contributing Development setup, architecture, testing

License

Licensed under the Apache License, Version 2.0. See the NOTICE file for attribution requirements.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bc_cli-0.1.3.tar.gz (362.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bc_cli-0.1.3-py3-none-any.whl (142.9 kB view details)

Uploaded Python 3

File details

Details for the file bc_cli-0.1.3.tar.gz.

File metadata

  • Download URL: bc_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 362.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for bc_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 270bf0317477747c99f46c4e3df094a8e549ea2a6a5d4eb08f5ff1317e870e38
MD5 c4cf992f074dc5e41eb8214cdb8eca91
BLAKE2b-256 bd4d556fd54f9797e525c976de407ad3670009bcfe9dcf4775552d108665499d

See more details on using hashes here.

Provenance

The following attestation bundles were made for bc_cli-0.1.3.tar.gz:

Publisher: publish.yml on igor-ctrl/bcli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bc_cli-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: bc_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 142.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for bc_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 32660d8588ee7a47a3b992de0c739bff86e361871351192f8ffd03a15e1a4edc
MD5 ef24ce440f198a7e82da6c98fd438509
BLAKE2b-256 d1ec863c4b998615e9fc58bb39b4da8be6353d6dff1adf3ff99f5633597dc24a

See more details on using hashes here.

Provenance

The following attestation bundles were made for bc_cli-0.1.3-py3-none-any.whl:

Publisher: publish.yml on igor-ctrl/bcli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page