Skip to main content

Python SDK for HR Platform API - Type-safe access with async support and pandas integration

Project description

hr-platform-sdk

Type-safe Python SDK for the HR Platform API with built-in retry logic, async support, and pandas integration.

Installation

pip install hr-platform-sdk

For pandas DataFrame integration:

pip install hr-platform-sdk[pandas]

Quick Start

API Key Authentication (Service-to-Service)

For integrations with external systems like Microsoft D365 F&O:

from hr_platform import HRPlatformClient

client = HRPlatformClient.with_api_key(
    "hrp_live_xxx...",
    base_url="https://hr-platform.vercel.app"
)

with client:
    # List all records
    records = client.records.list()

    # Get analytics summary
    summary = client.analytics.get_summary(entity="BVD")

Cookie Authentication (Browser Apps)

For browser-based applications using session cookies:

from hr_platform import HRPlatformClient

client = HRPlatformClient.with_cookie_auth(
    base_url="https://hr-platform.vercel.app"
)

with client:
    # Get current user profile
    profile = client.users.get_profile()

Async Usage

import asyncio
from hr_platform import AsyncHRPlatformClient

async def main():
    client = AsyncHRPlatformClient.with_api_key("hrp_live_xxx...")

    async with client:
        # Concurrent requests
        records, summary = await asyncio.gather(
            client.records.list(),
            client.analytics.get_summary()
        )

asyncio.run(main())

Features

  • Type-Safe - Full type hints with Pydantic v2 models
  • Async Support - Native asyncio with AsyncHRPlatformClient
  • Retry Logic - Automatic retries with exponential backoff for transient failures
  • Rate Limit Handling - Respects Retry-After headers from rate limit responses
  • Error Classes - Typed exception classes for different HTTP status codes
  • pandas Integration - Convert records and analytics to DataFrames (optional dependency)
  • Python 3.9+ - Works with Python 3.9, 3.10, 3.11, and 3.12

Configuration

Full Configuration Options

from hr_platform import HRPlatformClient
from hr_platform.core.config import RetryConfig

client = HRPlatformClient.with_api_key(
    "hrp_live_xxx...",
    base_url="https://hr-platform.vercel.app",
    api_version="v1",  # default: "v1"
    timeout=30.0,  # default: 30.0 seconds
    retry=RetryConfig(
        max_retries=3,  # default: 3
        initial_delay=1.0,  # default: 1.0 seconds
        max_delay=30.0,  # default: 30.0 seconds
        backoff_multiplier=2.0,  # default: 2.0
    ),
)

Resources

The SDK provides typed access to all HR Platform API resources:

Resource Description
client.records HR records CRUD and workflow operations
client.analytics Analytics, trends, and entity breakdowns
client.users User management and profiles
client.admin System administration (requires admin role)
client.compliance GDPR compliance document flow
client.webhooks Webhook subscription management

API Reference

Records

# List all records (respects entity scoping)
records = client.records.list()

# List with filters
filtered = client.records.list(
    entity="BVD",
    year="2025",
    month="10",
    status="APPROVED"
)

# Get single record
record = client.records.get("record-uuid")

# Create record
result = client.records.create({
    "entity": "BVD",
    "year": 2025,
    "month": 11,
    "working_days": 21,
    "workforce": {
        "bc_male": 20,
        "bc_female": 5,
        # ... other fields
    },
    # ... capacity, absences, turnover, performance, financials
})

# Update record (only DRAFT status)
client.records.update("record-uuid", {
    "working_days": 22,
    # ... updated fields
})

# Delete record (requires appropriate permissions)
client.records.delete("record-uuid")

# Workflow actions
client.records.submit("record-uuid")
client.records.approve("record-uuid")
client.records.reject("record-uuid", reason="Please correct the sick days")

Analytics

# Get summary metrics
summary = client.analytics.get_summary(
    entity="BVD",  # or "All"
    year="2025",
    month="10"
)
print(f"Total headcount: {summary.total_headcount}")
print(f"Total costs: EUR {summary.total_costs:,.2f}")

# Get trend data for charts
trends = client.analytics.get_trends(entity="BVD")
for trend in trends:
    print(f"{trend.month}/{trend.year}: {trend.headcount} employees")

# Get entity breakdown
breakdown = client.analytics.get_by_entity()
for entity in breakdown:
    print(f"{entity.entity}: {entity.total_headcount} headcount")

Users

# Get current user profile
profile = client.users.get_profile()
print(f"Logged in as: {profile.name} ({profile.role})")

# Change password
client.users.change_password(
    current_password="old-password",
    new_password="new-secure-password"
)

# Get password policy
policy = client.users.get_password_policy()
print(f"Min length: {policy.policy.min_length}")

# User management (requires system_admin role)
users = client.users.list()
user = client.users.get("user-uuid")
client.users.create({
    "name": "New User",
    "email": "user@example.com",
    "password": "SecurePass123!",
    "role": "local_partner",
    "entity": "BVD"
})
client.users.update("user-uuid", {"role": "group_head"})
client.users.delete("user-uuid")

Admin (requires system_admin role)

# System status
status = client.admin.get_status()
security = client.admin.get_security_dashboard()
print(f"Failed logins (24h): {security.failed_logins_24h}")

# User administration
client.admin.block_user("user-uuid")
client.admin.unblock_user("user-uuid")
result = client.admin.reset_password("user-uuid")
print(f"Temporary password: {result.temp_password}")

# Session management
sessions = client.admin.list_sessions()
client.admin.force_logout("user-uuid")

# Audit logs
logs = client.admin.get_audit_logs(
    page=1,
    limit=25,
    category="auth",
    severity="warning"
)

# API key management
keys = client.admin.list_api_keys()
result = client.admin.create_api_key({
    "name": "Integration Key",
    "userId": "user-uuid",
    "scopes": ["records:read", "analytics:read"],
    "expiresInDays": 365
})
print(f"API Key (save this!): {result.plain_text_key}")
client.admin.revoke_api_key("key-uuid")
new_key = client.admin.rotate_api_key("key-uuid")

Compliance

# Get compliance status
status = client.compliance.get_status()
if status.pending_documents:
    print(f"Documents pending: {len(status.pending_documents)}")

# Get compliance documents
documents = client.compliance.get_documents()
doc = client.compliance.get_document("privacy_notice")
print(f"Document: {doc.title} (v{doc.version})")

# Acknowledge document
client.compliance.acknowledge(
    document_type="privacy_notice",
    document_version="1.0.0",
    document_content_hash=doc.content_hash
)

# Complete compliance flow
client.compliance.complete()

# Admin: compliance overview (requires system_admin)
overview = client.compliance.get_admin_overview()
print(f"Completed: {overview.summary.completed_users}/{overview.summary.total_users}")
client.compliance.reset_user("user-uuid")

Webhooks

# List subscriptions
subscriptions = client.webhooks.list()

# Create subscription
webhook = client.webhooks.create({
    "name": "My Webhook",
    "url": "https://example.com/webhook",
    "events": ["record.created", "record.approved"]
})
print(f"Created webhook: {webhook.id}")

# Update subscription
client.webhooks.update("subscription-uuid", {"enabled": False})

# Delete subscription
client.webhooks.delete("subscription-uuid")

# Test webhook
result = client.webhooks.test("subscription-uuid")
print(f"Test result: {result.status_code}")

# Get delivery history
history = client.webhooks.get_delivery_history(
    "subscription-uuid",
    page=1,
    limit=50
)

# Get available event types
event_types = client.webhooks.get_event_types()
for event in event_types.events:
    print(f"{event.type}: {event.description}")

Error Handling

The SDK provides typed exception classes for different failure scenarios:

from hr_platform import HRPlatformClient
from hr_platform.exceptions import (
    HRPlatformError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    AuthenticationError,
    AuthorizationError,
    ConflictError,
    ServerError,
    NetworkError,
    TimeoutError,
)

try:
    record = client.records.get("invalid-id")
except NotFoundError as e:
    print(f"Record not found: {e.message}")
    print(f"Resource type: {e.resource_type}")
    print(f"Resource ID: {e.resource_id}")
except ValidationError as e:
    print(f"Validation errors on {len(e.fields)} fields:")
    for field in e.fields:
        print(f"  {field['field']}: {field['message']}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except AuthenticationError:
    print("Invalid or expired credentials")
except AuthorizationError:
    print("Insufficient permissions")
except ConflictError as e:
    print(f"Resource conflict: {e.message}")
except ServerError as e:
    print(f"Server error ({e.status}): {e.message}")
except NetworkError as e:
    print(f"Network error: {e.message}")
except TimeoutError as e:
    print(f"Request timed out after {e.timeout}s")
except HRPlatformError as e:
    # Base class for all SDK errors
    print(f"API error [{e.status}]: {e.message}")

Exception Hierarchy

HRPlatformError (base class)
├── AuthenticationError (401)
├── AuthorizationError (403)
├── NotFoundError (404)
│   ├── resource_type: str | None
│   └── resource_id: str | None
├── ValidationError (400)
│   └── fields: list[dict]
├── RateLimitError (429)
│   ├── retry_after: int | None
│   └── limit: int | None
├── ConflictError (409)
├── ServerError (500-599)
├── NetworkError (connection issues)
│   └── __cause__: Exception
└── TimeoutError
    └── timeout: float

pandas Integration

Install with pandas support:

pip install hr-platform-sdk[pandas]

Convert API responses to DataFrames:

from hr_platform import HRPlatformClient
from hr_platform.utils import (
    records_to_dataframe,
    trends_to_dataframe,
    entity_breakdown_to_dataframe,
    summary_to_series,
)

with HRPlatformClient.with_api_key("hrp_live_xxx...") as client:
    # Records to DataFrame with flattened nested data
    records = client.records.list()
    df_records = records_to_dataframe(records, flatten=True)
    print(df_records.shape)
    print(df_records.columns.tolist())

    # Group by entity
    print(df_records.groupby("entity")["total_headcount"].sum())

    # Trends to DataFrame with period column
    trends = client.analytics.get_trends()
    df_trends = trends_to_dataframe(trends, include_period=True)
    # Period format: "2025-01", "2025-02", etc.

    # Pivot table for sick rate analysis
    pivot = df_trends.pivot_table(
        values="sick_rate",
        index="period",
        columns="entity",
        aggfunc="mean"
    )

    # Entity breakdown as indexed DataFrame
    breakdown = client.analytics.get_by_entity()
    df_entities = entity_breakdown_to_dataframe(breakdown)
    # Access: df_entities.loc["BVD", "total_headcount"]

    # Summary as pandas Series
    summary = client.analytics.get_summary()
    series = summary_to_series(summary, name="Overall")
    print(series)

Export to CSV (German Excel format)

# German format: semicolon delimiter, comma decimal
df_records.to_csv(
    "records.csv",
    sep=";",
    decimal=",",
    index=False,
    encoding="utf-8-sig",  # BOM for Excel
)

Export to Excel

import pandas as pd

with pd.ExcelWriter("hr_report.xlsx") as writer:
    df_records.to_excel(writer, sheet_name="Records")
    df_trends.to_excel(writer, sheet_name="Trends")
    df_entities.to_excel(writer, sheet_name="Entities")

Async Examples

Concurrent Requests

import asyncio
from hr_platform import AsyncHRPlatformClient

async def fetch_all_data():
    client = AsyncHRPlatformClient.with_api_key("hrp_live_xxx...")

    async with client:
        # Run multiple requests concurrently - much faster than sequential!
        records, summary, trends, breakdown = await asyncio.gather(
            client.records.list(),
            client.analytics.get_summary(),
            client.analytics.get_trends(),
            client.analytics.get_by_entity(),
        )

        return records, summary, trends, breakdown

# Run
records, summary, trends, breakdown = asyncio.run(fetch_all_data())

Error Handling in Concurrent Requests

import asyncio
from hr_platform import AsyncHRPlatformClient

async def fetch_with_error_handling():
    client = AsyncHRPlatformClient.with_api_key("hrp_live_xxx...")

    async with client:
        # return_exceptions=True prevents one failure from canceling others
        results = await asyncio.gather(
            client.records.list(entity="BVD"),
            client.records.list(entity="VHH"),
            client.analytics.get_summary(),
            return_exceptions=True,
        )

        for i, result in enumerate(results):
            if isinstance(result, Exception):
                print(f"Request {i} failed: {result}")
            else:
                print(f"Request {i} succeeded: {type(result).__name__}")

asyncio.run(fetch_with_error_handling())

Fetch Multiple Records Concurrently

import asyncio
from hr_platform import AsyncHRPlatformClient

async def fetch_records_by_ids(record_ids: list[str]):
    client = AsyncHRPlatformClient.with_api_key("hrp_live_xxx...")

    async with client:
        records = await asyncio.gather(
            *[client.records.get(rid) for rid in record_ids]
        )
        return records

# Fetch 10 records concurrently
record_ids = ["uuid-1", "uuid-2", "uuid-3", ...]
records = asyncio.run(fetch_records_by_ids(record_ids))

Type Hints

The SDK provides full type hints via Pydantic models:

from hr_platform.models import (
    # Records
    FullHRRecord,
    Workforce,
    Capacity,
    Absences,
    Turnover,
    Performance,
    Financials,

    # Analytics
    AnalyticsSummary,
    AnalyticsTrend,
    EntityBreakdown,

    # Users
    User,
    UserProfile,
    PasswordPolicy,

    # Admin
    SystemStatus,
    SecurityDashboard,
    AuditLogEntry,
    ApiKey,

    # Compliance
    ComplianceStatus,
    ComplianceDocument,

    # Webhooks
    WebhookSubscription,
    WebhookDelivery,
    WebhookEventType,
)

# Type checking works!
def process_records(records: list[FullHRRecord]) -> int:
    return sum(r.workforce.bc_male + r.workforce.bc_female for r in records)

Development

Running Tests

# Install dev dependencies
pip install hr-platform-sdk[dev]

# Run tests with coverage
pytest

# Type checking
mypy hr_platform

# Linting
ruff check hr_platform
ruff format hr_platform

Requirements

  • Python 3.9+
  • httpx >= 0.27.0
  • pydantic >= 2.0.0
  • pandas >= 2.0.0 (optional, for DataFrame support)

License

MIT

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

hr_platform_sdk-0.1.0.tar.gz (55.2 kB view details)

Uploaded Source

Built Distribution

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

hr_platform_sdk-0.1.0-py3-none-any.whl (52.6 kB view details)

Uploaded Python 3

File details

Details for the file hr_platform_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: hr_platform_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 55.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for hr_platform_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ae0765a15350712a1fe8101e6a62b790479027dcef14be31d17e7c7aa54ae30f
MD5 f1257805a6c1e0f6252da231e1a3d05f
BLAKE2b-256 cb276aaf0326ab059c708593f5aaf7061ad30ff041a005665764e4f8174dcf96

See more details on using hashes here.

File details

Details for the file hr_platform_sdk-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for hr_platform_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8ad2461e905a6d5faaa1250d66922e9a4a4849489cade143a17d2dfef51c46f2
MD5 365f224f4127d8c87eab8bd0f9d80760
BLAKE2b-256 0c64ef98446cc8c27b9a2e5173e05fa1a3c59a55f937c98970a0ed2091ec2df8

See more details on using hashes here.

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