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:1per_page(int): Items per page (10, 20, 50, 100, 200). Default:100modified_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 datetimeapproval_right_date(str, optional): Filter for invoices approved before datetimestatus(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 identifierexternal_id(str): External system identifierintegration_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-Afterheader, 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
390c0d70f3221b9cc9e49746a8044a2d613294356b59d81d81eebc88fb6e80bf
|
|
| MD5 |
aa902be50b459880298809f4607cf1dc
|
|
| BLAKE2b-256 |
35108f75b949a8a2ff36c24e838238aa49e2e9dbb8cd45a1d0c266f8a5965b54
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fff3f996d852e6660e13e36f0efa92e711a7236bbe4ba9f4e9df3e7837a7fdd
|
|
| MD5 |
081ea903ff3abc46b65f881f930cb9f9
|
|
| BLAKE2b-256 |
fad7be27c6641a33acb0a91f085737caae6b46da403b2a13306d992101562f0f
|