Skip to content

Valentina Noir Python Client

The valentina-python-client package is an async and sync Python client for the Valentina Noir REST API. It wraps the API in type-safe Pydantic models, handles pagination and retries automatically, and lets you focus on building your application instead of managing HTTP requests.

Note

This client library is a convenience for Python developers. It isn't required to use the Valentina Noir API — you can integrate with any HTTP client in any language by following the full API documentation.

Why Use This Client?

You can call the Valentina Noir API directly with any HTTP library, but this client removes the boilerplate:

  • Type safety — Every request and response is validated through Pydantic models, catching errors early and giving you full IDE autocompletion.
  • Automatic pagination — Stream through large result sets with iter_all() or fetch everything at once with list_all(), without writing pagination logic yourself.
  • Built-in retries — Rate limits (429), server errors (5xx), and network failures are retried automatically with exponential backoff.
  • Async and sync — Built on httpx with both async (VClient) and sync (SyncVClient) clients, so it fits naturally into any Python application — from async frameworks like FastAPI to traditional sync code in Flask, Django, or scripts.
  • Idempotency support — Enable automatic idempotency keys so retried writes don't create duplicate resources.
  • Structured logging — Optional Loguru-based logging with a stdlib bridge for debugging and observability.

Requirements

Installation

# Using uv
uv add valentina-python-client

# Using pip
pip install valentina-python-client

Quick Start

Create a client once at application startup, then access API services from anywhere in your code.

Async

import asyncio
from vclient import VClient, companies_service, campaigns_service

async def main():
    async with VClient(
        base_url="https://api.valentina-noir.com",
        api_key="YOUR_API_KEY",
    ) as client:
        # List all companies you have access to
        companies = companies_service()
        for company in await companies.list_all():
            print(f"Company: {company.name}")

        # Fetch campaigns for a specific user
        campaigns = campaigns_service(
            user_id="USER_ID",
            company_id="COMPANY_ID",
        )
        for campaign in await campaigns.list_all():
            print(f"Campaign: {campaign.name}")

asyncio.run(main())

Sync

from vclient import SyncVClient, sync_companies_service, sync_campaigns_service

with SyncVClient(
    base_url="https://api.valentina-noir.com",
    api_key="YOUR_API_KEY",
) as client:
    # List all companies you have access to
    companies = sync_companies_service()
    for company in companies.list_all():
        print(f"Company: {company.name}")

    # Fetch campaigns for a specific user
    campaigns = sync_campaigns_service(
        user_id="USER_ID",
        company_id="COMPANY_ID",
    )
    for campaign in campaigns.list_all():
        print(f"Campaign: {campaign.name}")

You can also set VALENTINA_CLIENT_BASE_URL and VALENTINA_CLIENT_API_KEY as environment variables and create either client with no arguments.

Learn More

Detailed guides are available for each aspect of the client:

Topic Description
Configuration Timeouts, retries, environment variables, idempotency, and logging
Sync Client Using the synchronous client for non-async applications
Services Available services, method signatures, scoping, and pagination patterns
Response Models Pydantic model specifications for all API resources
Error Handling Exception hierarchy, HTTP status mapping, and usage examples
Testing Fake client for testing downstream applications against the vclient contract

Resources