Skip to main content

Python SDK for the ServiceTrade REST API

Project description

ServiceTrade Python SDK

A Python client for the ServiceTrade REST API with OAuth2 authentication and automatic token refresh.

Installation

pip install servicetrade

Quick Start

Using Client Credentials

from servicetrade import ServicetradeClient

client = ServicetradeClient(
    client_id="your-client-id",
    client_secret="your-client-secret"
)

# No need to call login() — the SDK authenticates lazily on the first API call.
jobs = client.get("/job")
print(jobs)

Using Refresh Token

from servicetrade import ServicetradeClient

client = ServicetradeClient(
    refresh_token="your-refresh-token"
)

jobs = client.get("/job")

Using a Pre-existing Token

from servicetrade import ServicetradeClient

client = ServicetradeClient(
    token="your-bearer-token",
    # Provide credentials for auto-refresh when the token expires
    client_id="your-client-id",
    client_secret="your-client-secret"
)

# No login needed if token is valid
jobs = client.get("/job")

API Methods

HTTP Methods

# GET request
result = client.get("/job/123")

# GET with query parameters
jobs = client.get("/job", params={"status": "scheduled", "locationId": 456})

# POST request
job = client.post("/job", {
    "type": "inspection",
    "description": "Quarterly HVAC Inspection",
    "locationId": 123,
    "vendorId": 456,
})

# PUT request
client.put("/job/123", {"description": "Updated Inspection Description"})

# DELETE request (returns None)
client.delete("/location/456")

Paginator

Iterate over all pages of a paginated endpoint automatically:

from servicetrade import Paginator, ServicetradeClient, ServicetradeAPIError

client = ServicetradeClient(
    client_id="your-client-id",
    client_secret="your-client-secret"
)

paginator = Paginator(client, "/job", "jobs", params={"status": "scheduled"})
try:
    for job in paginator:
        print(f"Job #{job['id']}: {job['description']}")
except ServicetradeAPIError as e:
    print(f"Error during pagination: {e.message}")

The Paginator constructor takes:

  • client — a ServicetradeClient instance
  • path — the API endpoint path (e.g., "/job")
  • items_key — the key in the response that contains the list of items (e.g., "jobs")
  • params — optional dict of query parameters to include on every request

File Attachments

from servicetrade import ServicetradeClient, FileAttachment

client = ServicetradeClient(client_id="your-client-id", client_secret="your-client-secret")

# Upload a file
file = FileAttachment(
    value=b"file contents here",
    filename="document.pdf",
    content_type="application/pdf"
)

result = client.attach(
    {"entityType": 3, "entityId": 123, "purposeId": 7},
    file
)

Reading from a file path

from pathlib import Path
from servicetrade import FileAttachment

file = FileAttachment(
    value=Path("/path/to/document.pdf"),
    filename="document.pdf",
    content_type="application/pdf"
)

Response Handling

Return values

  • get(), post(), put() return the data field from the response when present, or the full response dict/list otherwise.
  • delete() returns None.
  • When fetching a single resource by ID (e.g., /job/123), the response is a dict. When querying a collection (e.g., /job), the response may be a dict containing a list under a resource-specific key (e.g., "jobs").

Accessing the full response

Use get_last_response() to access status code, headers, and full body:

result = client.get("/job/123")
response = client.get_last_response()

print(response.status_code)   # 200
print(response.is_success())  # True
print(response.body)          # Full response body (dict)
print(response.headers)       # Response headers (dict)

Accessing the auth token

token = client.get_auth_token()

Configuration Options

client = ServicetradeClient(
    # API Configuration
    base_url="https://api.servicetrade.com",  # Default
    api_prefix="/api",                         # Default
    user_agent="My App/1.0",                   # Custom user agent

    # Authentication (pick one)
    client_id="your-client-id",
    client_secret="your-client-secret",
    # OR
    refresh_token="your-refresh-token",
    # OR
    token="your-bearer-token",

    # Options
    auto_refresh_auth=True,                    # Auto-refresh tokens (default)

    # Callbacks
    on_set_auth=lambda token: save_token(token),
    on_unset_auth=lambda: clear_token(),
)

Custom Headers

client.set_custom_header("X-Custom-Header", "value")

Error Handling

from servicetrade import (
    ServicetradeClient,
    ServicetradeAuthError,
    ServicetradeAPIError,
)

client = ServicetradeClient(client_id="your-client-id", client_secret="your-client-secret")

try:
    result = client.get("/nonexistent")
except ServicetradeAPIError as e:
    print(f"API error: {e.message}")
    print(f"Status code: {e.status_code}")
    print(f"Response data: {e.response_data}")

    # Structured errors from ServiceTrade API
    if e.error_messages:
        print(f"Errors: {e.error_messages}")
    if e.validation:
        print(f"Validation: {e.validation}")

Authentication Flow

The SDK supports two OAuth2 grant types, prioritized in this order:

  1. Refresh Token Grant — Most secure, only stores refresh token
  2. Client Credentials Grant — For service-to-service authentication

Lazy Authentication

The SDK automatically authenticates on the first API call if no token exists. You can also call login() explicitly for eager authentication:

client = ServicetradeClient(client_id="your-client-id", client_secret="your-client-secret")

# Eager authentication (optional)
client.login()

# Or just make API calls — login happens automatically
jobs = client.get("/job")

Automatic Token Refresh

By default, the SDK automatically refreshes tokens when:

  • A request returns a 401 Unauthorized response
  • The token is about to expire (within 5 minutes of expiry)

To disable automatic refresh:

client = ServicetradeClient(
    client_id="id",
    client_secret="secret",
    auto_refresh_auth=False
)

Development

Setup

# Clone the repository
git clone https://github.com/servicetrade/servicetrade-python-sdk.git
cd servicetrade-python-sdk

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

Running Tests

pytest

Type Checking

mypy src

License

MIT License - see LICENSE file for details.

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

servicetrade-1.0.0.tar.gz (9.8 kB view details)

Uploaded Source

Built Distribution

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

servicetrade-1.0.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file servicetrade-1.0.0.tar.gz.

File metadata

  • Download URL: servicetrade-1.0.0.tar.gz
  • Upload date:
  • Size: 9.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for servicetrade-1.0.0.tar.gz
Algorithm Hash digest
SHA256 708df3245209322e86749548592c4903799843946cb90ea2c96241da6e57b25f
MD5 eed2b5bc730d42c796f7ec0bdb10f67f
BLAKE2b-256 3c28d5a8694a46f379524abd73c0609284377fd0e8c08d07fe79eb4d4fe63f43

See more details on using hashes here.

Provenance

The following attestation bundles were made for servicetrade-1.0.0.tar.gz:

Publisher: publish.yml on servicetrade/servicetrade-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file servicetrade-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: servicetrade-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for servicetrade-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 02d93e85dd46af295797ea8a025d5d49a1e8894b62378623abd1e1f3334ca413
MD5 6c849fc9768019d835d1504c5fead549
BLAKE2b-256 6ae8a53fcfbc4a6f6ea4e408a064d845dded553ee817a6f18f1daca49f7c454c

See more details on using hashes here.

Provenance

The following attestation bundles were made for servicetrade-1.0.0-py3-none-any.whl:

Publisher: publish.yml on servicetrade/servicetrade-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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