PyXero
PyXero is a community-maintained Python library for accessing the Xero accounting software's REST API. It provides a convenient object-oriented interface to interact with various Xero entities like contacts, invoices, and accounts. The library is actively maintained with irregular but consistent releases, primarily focusing on supporting Xero's evolving API and compatible Python versions.
Common errors
-
ModuleNotFoundError: No module named 'xero'
cause You installed the `pyxero` package but are trying to import it using an incorrect name (e.g., `import pyxero`) or it's not installed correctly.fixEnsure you have installed `pip install pyxero` and are importing with `from xero import ...` (note the `xero` module name, not `pyxero`). -
xero.exceptions.XeroException: Unauthorized (HTTP 401)
cause Your OAuth2 access token is either invalid, expired, or does not have the necessary scopes. Alternatively, the `tenant_id` might be incorrect or you lack access to it.fixObtain a fresh access token through the OAuth2 flow, ensure it has the required scopes, and verify your `XERO_TENANT_ID` is correct and accessible to the provided token. -
This Python version (X.X.X) is not supported
cause You are running a version of Python that is no longer supported by your `pyxero` version (e.g., Python 3.8 or older for `pyxero` v0.9.5+).fixUpgrade your Python environment to 3.9 or higher (the current minimum for `pyxero` v0.9.5). -
AttributeError: 'Xero' object has no attribute 'private_application'
cause You are attempting to use the `PrivateApplication` class or related methods which were entirely removed from `pyxero` in `v0.9.3`.fixMigrate your authentication logic to use `xero.oauth2.XeroOAuth2` and the OAuth2 authorization flow, as OAuth1 Private Apps are no longer supported.
Warnings
- breaking Python 3.8 support was dropped in `v0.9.5`, making Python 3.9+ the minimum requirement. Earlier versions (v0.9.4) dropped Python 3.7, and (v0.9.2) dropped 2.7/3.4.
- breaking Support for OAuth1 Private Applications was entirely removed in `v0.9.3`. PyXero now primarily supports OAuth2, aligning with Xero's own API deprecation roadmap for OAuth1.
- gotcha The PyPI package name is `pyxero`, but the actual Python import statement uses `from xero import ...`. This is a common source of `ModuleNotFoundError` if you attempt to import `pyxero` directly.
- breaking As of `v0.9.5`, usage of the Files API now explicitly includes the `tenant-id` in requests. While `pyxero` handles this if the `Xero` client is initialized correctly, older code that bypasses the client or doesn't pass a tenant_id might break.
Install
-
pip install pyxero
Imports
- Xero
from pyxero import Xero
from xero import Xero
- XeroOAuth2
from pyxero.oauth2 import XeroOAuth2
from xero.oauth2 import XeroOAuth2
Quickstart
import os
from xero import Xero
# Set these environment variables with your Xero OAuth2 credentials:
# XERO_ACCESS_TOKEN: Your active Xero OAuth2 access token.
# XERO_TENANT_ID: The Xero organization (tenant) ID you want to connect to.
# To obtain these, you must first complete the Xero OAuth2 authorization flow
# (involving redirecting a user to Xero for consent and obtaining tokens).
access_token = os.environ.get('XERO_ACCESS_TOKEN', '')
tenant_id = os.environ.get('XERO_TENANT_ID', '')
if not access_token:
print("Error: Please set the XERO_ACCESS_TOKEN environment variable.")
print("Refer to pyxero documentation for OAuth2 authorization flow details.")
exit(1)
if not tenant_id:
print("Error: Please set the XERO_TENANT_ID environment variable.")
print("You can find the tenant ID after completing the OAuth2 authorization.")
exit(1)
try:
xero = Xero(tenant_id, access_token)
# Example: Fetch the first 5 contacts
contacts = xero.contacts.all()
print(f"Successfully fetched {len(contacts)} contacts. Displaying first 5:")
for i, contact in enumerate(contacts):
if i >= 5:
break
print(f"- {contact.Name} (ID: {contact.ContactID})")
except Exception as e:
print(f"An error occurred: {e}")
print("Please ensure your XERO_ACCESS_TOKEN and XERO_TENANT_ID are valid and have the necessary permissions.")