Skip to main content

Python SDK for Precoro API

Project description

Precoro Python SDK

A production-ready synchronous Python client for the Precoro API.

Features

  • Synchronous blocking I/O using requests
  • Full type hints (PEP 484) for excellent IDE support
  • Automatic retry logic with exponential backoff for rate limits and server errors
  • Pagination support with auto-pagination helper methods
  • Comprehensive error handling with custom exception hierarchy
  • Thread-safe when using separate client instances per thread

Installation

# Install in editable mode with development dependencies
pip install -e ".[dev]"

# Or install from PyPI (when published)
pip install precoro-sdk

Quick Start

from precoro import PrecoroClient

# Initialize the client
client = PrecoroClient(
    token="your_company_token",
    email="your@email.com",
    base_url="https://api.precoro.com",  # or https://api.precoro.us
)

# Fetch a page of invoices
invoices = client.invoices.list(per_page=50)
print(f"Total invoices: {invoices['meta']['pagination']['total']}")

# Iterate through invoice data
for invoice in invoices['data']:
    print(f"Invoice {invoice['idn']}: ${invoice['totalAmount']}")

# Get a specific invoice by IDN
invoice = client.invoices.get("12345")
print(invoice['vendorName'])

# Auto-paginate through all invoices with filters
all_approved = client.invoices.list_all(
    status=[2],  # 2 = approved
    modified_since="2025-01-01T00:00:00"
)
print(f"Found {len(all_approved)} approved invoices")

# Set external ID for integration
client.invoices.set_external_id(
    idn="12345",
    external_id="QB-INV-789",
    integration_log="Synced from QuickBooks"
)

# Always close the client when done
client.close()

Using Context Manager (Recommended)

from precoro import PrecoroClient

with PrecoroClient(token="xxx", email="user@example.com") as client:
    invoices = client.invoices.list(per_page=100)
    # Client automatically closes when exiting the context

API Documentation

PrecoroClient

Main client class for accessing Precoro API resources.

Parameters:

  • token (str): Company API token (X-AUTH-TOKEN header)
  • email (str): User email address (email header)
  • base_url (str): API base URL. Options:
    • https://api.precoro.com (International, default)
    • https://api.precoro.us (United States)
  • timeout (tuple[float, float]): HTTP timeout as (connect, read) in seconds. Default: (5.0, 30.0)
  • max_retries (int): Maximum retry attempts for retryable errors. Default: 3

Resources:

Attribute Resource Endpoint
client.invoices Invoices & Credit Notes /invoices
client.purchase_orders Purchase Orders /purchaseorders
client.purchase_requisitions Purchase Requisitions /purchaserequisitions
client.request_for_proposals Requests for Proposals /requestforproposals
client.receipts Receipts /receipts
client.expenses Expenses /expenses
client.payments Payments & Expense Payments /payments, /expensePayments
client.budgets Budgets /budgets
client.warehouse_requests Warehouse Requests /warehouserequests
client.ocr AP Documents (OCR) /ap/documents
client.inventory Stock Transfers, Stock-takings, Warehouse Items /stocktransfers, /stock_takings
client.suppliers Suppliers /suppliers
client.items Catalog Items /items
client.supplier_custom_fields Supplier Custom Fields /suppliercustomfields
client.item_custom_fields Item Custom Fields /itemcustomfields
client.document_custom_fields Document Custom Fields /documentcustomfields
client.units Measurement Units /units
client.contracts Contracts /contracts
client.payment_terms Payment Terms /paymentterms
client.locations Company Locations /locations
client.users Company Users /users
client.legal_entities Legal Entities /legalentities
client.warehouses Warehouses /warehouses
client.taxes Taxes /taxes
client.attachments Attachments /attachments
client.approval Approval (approve / reject / revise) per document type

InvoicesResource

Methods for interacting with invoices.

list(page, per_page, **filters)

Fetch a single page of invoices.

Parameters:

  • page (int): Page number (1-indexed). Default: 1
  • per_page (int): Items per page (10, 20, 50, 100, 200). Default: 100
  • modified_since (str, optional): Filter for invoices modified after datetime (format: "2022-12-12T00:00:00")
  • approval_left_date (str, optional): Filter for invoices approved after datetime
  • approval_right_date (str, optional): Filter for invoices approved before datetime
  • status (list[int], optional): Filter by status IDs (e.g., [2, 4])
  • logic_type (list[int], optional): Filter by logic type (0=standard, 1=credit note, 2=PO-based)

Returns: dict with "data" (list of invoices) and "meta" (pagination info)

list_all(per_page, **filters)

Auto-paginate through all invoices. Accepts same filters as list() except page.

Returns: list[dict] - Flat list of all invoices

get(idn)

Fetch a single invoice by IDN.

Parameters:

  • idn (str): Internal company identifier

Returns: dict - Invoice object (not wrapped in "data")

set_external_id(idn, external_id, integration_log=None)

Set the externalId field on an invoice.

Parameters:

  • idn (str): Internal company identifier
  • external_id (str): External system identifier
  • integration_log (str, optional): Integration log message

Returns: dict - Updated invoice object

Error Handling

The SDK provides a comprehensive exception hierarchy:

from precoro import (
    PrecoroError,              # Base exception
    PrecoroAPIError,           # Base for HTTP errors
    PrecoroAuthenticationError, # 401/403 errors
    PrecoroRateLimitError,     # 429 errors
    PrecoroClientError,        # Other 4xx errors
    PrecoroServerError,        # 5xx errors
    PrecoroConnectionError,    # Network failures
)

try:
    invoice = client.invoices.get("12345")
except PrecoroAuthenticationError:
    print("Invalid credentials")
except PrecoroRateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except PrecoroServerError as e:
    print(f"Server error: {e.status_code}")
except PrecoroConnectionError:
    print("Network connection failed")
except PrecoroError as e:
    print(f"Unexpected error: {e}")

Automatic Retries

The client automatically retries:

  • 429 (Rate Limit): Respects Retry-After header, falls back to exponential backoff
  • 5xx (Server Errors): Exponential backoff with jitter
  • Connection/Timeout Errors: Exponential backoff with jitter

Not retried:

  • 401/403 (Authentication errors)
  • Other 4xx (Client errors)

Logging

The SDK uses Python's standard logging module with the logger name "precoro".

import logging

# Enable debug logging to see all HTTP requests
logging.basicConfig(level=logging.DEBUG)

# Or configure just the Precoro logger
logger = logging.getLogger("precoro")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
logger.addHandler(handler)

# Now all requests will be logged
client = PrecoroClient(token="xxx", email="user@example.com")
invoices = client.invoices.list()
# Output: 2025-02-16 10:30:00 - precoro - DEBUG - GET https://api.precoro.com/invoices -> 200 (0.45s)

Log Levels:

  • DEBUG: HTTP requests (method, URL, status, response time)
  • WARNING: Retry attempts (reason, attempt number, delay)
  • ERROR: Final failures after exhausting retries

Rate Limits

Precoro API rate limits:

  • 60 requests/minute (1 req/sec)
  • 1500 requests/hour
  • 3000 requests/day
  • Duplicate requests: 1/min, 30/hour

The SDK handles rate limiting automatically with retries.

Development

# Install dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run type checker
mypy precoro

# Run linter
ruff check precoro

# Format code
ruff format precoro

Thread Safety

Warning: The client uses requests.Session which is not thread-safe. Create a separate client instance for each thread:

from threading import Thread
from precoro import PrecoroClient

def fetch_invoices():
    # Create a new client per thread
    client = PrecoroClient(token="xxx", email="user@example.com")
    invoices = client.invoices.list()
    client.close()

threads = [Thread(target=fetch_invoices) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

License

MIT

Support

For issues and questions, please visit GitHub Issues.

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

precoro_sdk-0.1.0.tar.gz (46.5 kB view details)

Uploaded Source

Built Distribution

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

precoro_sdk-0.1.0-py3-none-any.whl (50.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for precoro_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 390c0d70f3221b9cc9e49746a8044a2d613294356b59d81d81eebc88fb6e80bf
MD5 aa902be50b459880298809f4607cf1dc
BLAKE2b-256 35108f75b949a8a2ff36c24e838238aa49e2e9dbb8cd45a1d0c266f8a5965b54

See more details on using hashes here.

File details

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

File metadata

  • Download URL: precoro_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 50.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for precoro_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0fff3f996d852e6660e13e36f0efa92e711a7236bbe4ba9f4e9df3e7837a7fdd
MD5 081ea903ff3abc46b65f881f930cb9f9
BLAKE2b-256 fad7be27c6641a33acb0a91f085737caae6b46da403b2a13306d992101562f0f

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