A modern, typed, and robust Python client for the Microsoft Dynamics 365 Business Central OData V4 API
Odyn provides a convenient and feature-rich interface for interacting with Microsoft Dynamics 365 Business Central, including automatic retry mechanisms, pagination handling, and pluggable authentication sessions.
- Type Safety: Fully typed with comprehensive type annotations for better IDE support and runtime safety.
- Automatic Retry Logic: Built-in exponential backoff retry mechanism for handling transient network failures.
- Smart Pagination: Automatic handling of OData pagination with transparent multi-page data retrieval.
- Flexible Authentication: Pluggable
requests.Sessionbased authentication. Comes withBearerAuthSessionandBasicAuthSessionout of the box. - Comprehensive Logging: Detailed logging with
loguruintegration for easy debugging and monitoring. - Production Ready: Robust error handling, validation, and timeout management.
- Extensible Design: Easily extendable to support custom authentication strategies or other session-level features.
pip install odynOr see full installation instructions for pip, uv, and poetry.
from odyn import Odyn, BearerAuthSession
# Create an authenticated session
session = BearerAuthSession("your-access-token")
# Initialize the client
client = Odyn(
base_url="https://your-tenant.businesscentral.dynamics.com/api/v2.0/",
session=session
)
# Fetch data with automatic pagination
customers = client.get("customers")
print(f"Retrieved {len(customers)} customers")
# Use OData query parameters
filtered_customers = client.get(
"customers",
params={
"$top": 10,
"$filter": "contains(name, 'Adventure')",
"$select": "id,name,phoneNumber"
}
)- Python 3.12+
- requests (≥2.32.4)
- loguru (≥0.7.3)
- 📚 Full documentation: https://konspec.github.io/odyn/
- Installation - Install Odyn using pip, uv, or poetry
- Getting Started - Quick setup and first API call
- Odyn Client - Complete API reference for the main client
- Authentication Sessions - Session management and authentication
- Exception Handling - Understanding and handling errors
- Configuration - Timeouts, retries, and advanced settings
- Logging - Logging behavior and customization
- FAQ - Frequently asked questions
- Troubleshooting - Common issues and solutions
from odyn import Odyn, BearerAuthSession
# Create a session with your bearer token
session = BearerAuthSession(token="your-access-token")
# Initialize the client
client = Odyn(
base_url="https://api.businesscentral.dynamics.com/v2.0/your-tenant-id/production/",
session=session,
)
# Get all customers with automatic pagination handling
customers = client.get("customers")
print(f"Retrieved {len(customers)} customers")
# Get the top 10 items, filtering by name and selecting specific fields
items = client.get(
"items",
params={
"$top": 10,
"$filter": "contains(displayName, 'Desk')",
"$select": "id,displayName,itemCategoryCode",
},
)
print(f"Filtered items: {items}")from odyn import Odyn, BasicAuthSession
# Create a session with your username and web service access key
session = BasicAuthSession(username="your-username", password="your-web-service-access-key")
# Initialize the client
client = Odyn(
base_url="https://api.businesscentral.dynamics.com/v2.0/your-tenant-id/production/",
session=session,
)
# Get all vendors
vendors = client.get("vendors")
print(f"Retrieved {len(vendors)} vendors")from odyn import Odyn, BearerAuthSession
from loguru import logger
# Bind a custom component to the logger for easy filtering
custom_logger = logger.bind(component="business-central-client")
# Create a session with custom retry settings
# This example uses a more aggressive retry strategy than the default.
session = BearerAuthSession(
token="your-token",
retries=10,
backoff_factor=0.5,
status_forcelist=[408, 429, 500, 502, 503, 504],
)
# Initialize a client with a custom timeout and the custom logger
client = Odyn(
base_url="https://api.businesscentral.dynamics.com/v2.0/your-tenant-id/production/",
session=session,
logger=custom_logger,
timeout=(10, 60), # 10s connect timeout, 60s read timeout
)from odyn import (
Odyn,
BearerAuthSession,
InvalidURLError,
InvalidSessionError,
InvalidTimeoutError,
InvalidLoggerError,
)
import requests
try:
# Intentionally create an invalid session
session = BearerAuthSession(token=None) # type: ignore
client = Odyn(base_url="not-a-valid-url", session=session)
client.get("customers")
except InvalidURLError as e:
print(f"Invalid URL: {e}")
except InvalidSessionError as e:
print(f"Invalid session: {e}")
except InvalidTimeoutError as e:
print(f"Invalid timeout configuration: {e}")
except InvalidLoggerError as e:
print(f"Invalid logger object provided: {e}")
except requests.exceptions.HTTPError as e:
# Handle HTTP errors (e.g., 401 Unauthorized, 404 Not Found)
print(f"HTTP Error: {e.response.status_code} - {e.response.text}")
except requests.exceptions.RequestException as e:
# Handle network-related errors (e.g., connection refused)
print(f"Network Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/konspec/odyn.git
cd odyn
# Install dependencies (we recommend using uv)
uv pip install -e .[dev]
# Run tests
pytest
# Run linting
ruff check .This project is licensed under the MIT License - see the LICENSE file for details.
- Microsoft Dynamics 365 Business Central OData Web Services
- OData V4 Specification
- requests - HTTP library
- loguru - Logging library
