Airbyte source connector for extracting data from the Xero accounting API with support for 21 data streams and incremental sync capabilities
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Configuration specification and authentication setup for connecting to the Xero API. This includes credential management, tenant identification, and sync boundary configuration with comprehensive validation and security features.
Complete specification of required and optional configuration parameters for connecting to Xero's API.
ConfigurationSpec = {
"type": "object",
"required": ["access_token", "tenant_id", "start_date"],
"additionalProperties": True,
"properties": {
"access_token": {
"type": "string",
"title": "Access Token",
"description": "Enter your Xero application's access token",
"airbyte_secret": True,
"order": 0
},
"tenant_id": {
"type": "string",
"title": "Tenant ID",
"description": "Enter your Xero organization's Tenant ID",
"airbyte_secret": True,
"order": 1
},
"start_date": {
"type": "string",
"title": "Start Date",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$",
"description": "UTC date and time in the format YYYY-MM-DDTHH:mm:ssZ. Any data with created_at before this data will not be synced.",
"examples": ["2022-03-01T00:00:00Z"],
"format": "date-time",
"order": 2
}
}
}
"""
Configuration schema for Xero source connector.
All three fields are required for successful connection:
- access_token: OAuth 2.0 bearer token for API authentication
- tenant_id: Xero organization identifier for multi-tenant access
- start_date: Defines the earliest date for incremental sync operations
"""Details on Xero API authentication using OAuth 2.0 bearer tokens with tenant-specific access control.
# Authentication headers automatically applied to all requests
AuthenticationHeaders = {
"Authorization": "Bearer {access_token}",
"Xero-Tenant-Id": "{tenant_id}",
"Accept": "application/json"
}
"""
HTTP headers used for Xero API authentication.
The connector automatically applies these headers to all API requests:
- Authorization: OAuth 2.0 bearer token authentication
- Xero-Tenant-Id: Required for multi-tenant Xero applications
- Accept: Specifies JSON response format preference
"""
# Base API configuration
APIConfiguration = {
"base_url": "https://api.xero.com/api.xro/2.0/",
"http_method": "GET",
"authenticator_type": "BearerAuthenticator"
}
"""
Core API configuration for Xero API endpoints.
All API calls use:
- HTTPS with Xero's standard API base URL
- GET method for data extraction (read-only operations)
- Bearer token authentication for security
"""Comprehensive error handling rules for different HTTP response scenarios with appropriate retry and failure strategies.
ErrorHandlingRules = {
"401_unauthorized": {
"action": "FAIL",
"error_message": "Failed to authorize request. Please update your access token to continue using the source."
},
"403_forbidden": {
"action": "IGNORE",
"description": "Permission denied for specific records - skip and continue"
},
"429_rate_limited": {
"action": "RETRY",
"backoff_strategy": {
"type": "ConstantBackoffStrategy",
"backoff_time_in_seconds": 30
}
}
}
"""
HTTP error handling configuration for robust API interactions.
Response handling strategies:
- 401: Authentication failure - halt sync with clear error message
- 403: Permission denied - skip individual records, continue sync
- 429: Rate limit exceeded - retry after 30 second delay
"""# Minimum required configuration
config = {
"access_token": "your_xero_access_token_here",
"tenant_id": "your_xero_tenant_id_here",
"start_date": "2023-01-01T00:00:00Z"
}
# Validate configuration format
import re
from datetime import datetime
def validate_config(config):
"""Validate configuration parameters."""
errors = []
# Check required fields
required_fields = ["access_token", "tenant_id", "start_date"]
for field in required_fields:
if field not in config or not config[field]:
errors.append(f"Missing required field: {field}")
# Validate start_date format
if "start_date" in config:
pattern = r"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
if not re.match(pattern, config["start_date"]):
errors.append("start_date must be in format YYYY-MM-DDTHH:mm:ssZ")
return len(errors) == 0, errors
# Validate the configuration
is_valid, validation_errors = validate_config(config)
if is_valid:
print("Configuration is valid")
else:
print("Configuration errors:", validation_errors)from source_xero import SourceXero
import logging
def test_connection(config):
"""Test connection with proper error handling."""
source = SourceXero()
logger = logging.getLogger(__name__)
try:
is_connected, error_message = source.check_connection(logger, config)
if is_connected:
print("✓ Successfully connected to Xero API")
return True
else:
print(f"✗ Connection failed: {error_message}")
# Handle common error scenarios
if "authorize" in error_message.lower():
print(" → Check your access_token is valid and not expired")
elif "tenant" in error_message.lower():
print(" → Verify your tenant_id is correct")
return False
except Exception as e:
print(f"✗ Connection test error: {str(e)}")
return False
# Test with configuration
config = {
"access_token": "your_token",
"tenant_id": "your_tenant",
"start_date": "2023-01-01T00:00:00Z"
}
connection_success = test_connection(config)# Configuration with additional properties
advanced_config = {
# Required fields
"access_token": "your_xero_oauth_token",
"tenant_id": "12345678-1234-1234-1234-123456789012",
"start_date": "2023-01-01T00:00:00Z",
# Additional properties (connector supports extensibility)
"request_timeout": 30,
"max_retries": 3,
"log_level": "INFO"
}
# Start date configuration examples
start_date_examples = {
"recent_data": "2023-12-01T00:00:00Z", # Last month
"current_year": "2024-01-01T00:00:00Z", # Current year
"historical": "2020-01-01T00:00:00Z", # Historical data
"specific_time": "2023-06-15T14:30:00Z" # Specific timestamp
}import os
from pathlib import Path
def load_secure_config():
"""Load configuration from environment variables for security."""
config = {
"access_token": os.getenv("XERO_ACCESS_TOKEN"),
"tenant_id": os.getenv("XERO_TENANT_ID"),
"start_date": os.getenv("XERO_START_DATE", "2023-01-01T00:00:00Z")
}
# Validate all required environment variables are set
missing_vars = [key for key, value in config.items() if not value]
if missing_vars:
raise ValueError(f"Missing environment variables: {missing_vars}")
return config
# Usage with environment variables
# export XERO_ACCESS_TOKEN="your_token_here"
# export XERO_TENANT_ID="your_tenant_id_here"
# export XERO_START_DATE="2023-01-01T00:00:00Z"
secure_config = load_secure_config()Common configuration issues and solutions:
def diagnose_config_issues(config, error_message):
"""Diagnose common configuration problems."""
suggestions = []
if "401" in error_message or "unauthorized" in error_message.lower():
suggestions.extend([
"Verify access_token is valid and not expired",
"Check token has required scopes: accounting.transactions.read, accounting.contacts.read",
"Ensure token was generated for the correct Xero application"
])
if "403" in error_message or "forbidden" in error_message.lower():
suggestions.extend([
"Verify tenant_id matches the organization you have access to",
"Check your Xero application has permission to access this tenant",
"Ensure the organization subscription includes required features"
])
if "tenant" in error_message.lower():
suggestions.extend([
"Verify tenant_id is in correct UUID format",
"Check tenant_id matches an organization you have access to",
"Try using the organization's short code instead if supported"
])
return suggestions
# Example usage
error_msg = "Failed to authorize request"
suggestions = diagnose_config_issues(config, error_msg)
for suggestion in suggestions:
print(f" → {suggestion}")Install with Tessl CLI
npx tessl i tessl/pypi-airbyte-source-xero