Skip to content

How-To Guides

Authenticate with the API

The recommended approach is to load credentials from environment variables (see Getting Started):

from dotenv import load_dotenv
from adpapi import AdpApiClient, AdpCredentials

load_dotenv()
credentials = AdpCredentials.from_env()
client = AdpApiClient(credentials)

You can also construct credentials manually if you prefer not to use environment variables:

credentials = AdpCredentials(
    client_id='your_client_id',
    client_secret='your_client_secret',
    cert_path='path/to/cert.pem',  # optional
    key_path='path/to/adp.key'    # optional
)
client = AdpApiClient(credentials)

Filter Results with OData

Use FilterExpression.field() to build type-safe OData filters to pass to call_endpoint or call_rest_endpoint:

from adpapi import FilterExpression

# Simple equality filter
filter_expr = FilterExpression.field('workers/workAssignments/assignmentStatus/statusCode/codeValue').eq('Active')

results = client.call_endpoint(
    endpoint="/hr/v2/workers",
    filters=filter_expr
)

Combine multiple conditions with & (AND) and | (OR):

active = FilterExpression.field('workers/workAssignments/assignmentStatus/statusCode/codeValue').eq('Active')
senior = FilterExpression.field('workers/workAssignments/seniorityDate').lt('2015-01-01')

results = client.call_endpoint(
    endpoint="/hr/v2/workers",
    filters=active & senior
)

You can also pass a raw OData string if you already have one:

results = client.call_endpoint(
    endpoint="/hr/v2/workers",
    filters="workers/workAssignments/assignmentStatus/statusCode/codeValue eq 'Active'"
)

Call a REST Endpoint with Path Parameters

Use call_rest_endpoint to call non-OData REST endpoints that contain path parameters:

# Single value — fetch one worker
results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID="G3349PRDL000001"
)

# List of values — batch fetch multiple workers in one call
results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID=["G3349PRDL000001", "G3349PRDL000002"]
)

You can also pass query parameters and change the HTTP method:

results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}/custom-fields",
    method="GET",
    masked=False,
    params={"$top": 10},
    associateOID="G3349PRDL000001"
)

Filter and Select with REST Endpoints

You can use select and filters with call_rest_endpoint, just like with call_endpoint:

from adpapi import FilterExpression

# Select specific columns
results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID=["G3349PRDL000001", "G3349PRDL000002"],
    select=["workers/person/legalName", "workers/workAssignments/assignmentStatus"]
)

# Apply filters
active_filter = FilterExpression.field("workers/workAssignments/assignmentStatus/statusCode/codeValue").eq("Active")
results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID=["G3349PRDL000001", "G3349PRDL000002"],
    filters=active_filter
)

# Combine both
results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID=["G3349PRDL000001", "G3349PRDL000002"],
    select=["workers/person/legalName", "workers/associateOID"],
    filters=active_filter
)

Speed Up Batch Requests with Parallel Fetching

When calling call_rest_endpoint with a list of IDs, the default behaviour is sequential, one request at a time. For large batches this can be slow. Use the max_workers parameter to parallelize requests across multiple threads:

aoid_list = get_aoids()  # e.g. a list of 50 associate OIDs

with AdpApiClient(credentials) as client:
    # Sequential (default) — ~44s for 50 workers
    results_slow = client.call_rest_endpoint(
        endpoint="/hr/v2/workers/{associateOID}",
        associateOID=aoid_list
    )

    # Parallel — ~8s for 50 workers with 10 threads (~5-10x faster)
    results_fast = client.call_rest_endpoint(
        endpoint="/hr/v2/workers/{associateOID}",
        max_workers=10,
        associateOID=aoid_list
    )

Choosing max_workers

max_workers Behaviour
1 (default) Sequential — one request at a time
510 Good starting range for most workloads
> 10 Diminishing returns; may trigger API rate limits

The token is refreshed once before the batch starts, so all threads share the same valid token, there is no risk of concurrent token refresh conflicts.

Preserve Request IDs in Responses

Some ADP endpoints do not include the requested identifier (e.g. the associate OID) in the response body. Use inject_path_params=True to merge the path parameters into each response dict so you never lose track of which response belongs to which ID:

results = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}",
    associateOID=["G3349PRDL000001", "G3349PRDL000002"],
    inject_path_params=True,
)

# Each response now contains the associateOID that produced it
for worker in results:
    print(worker["associateOID"], worker["workers"])
    # "G3349PRDL000001" [...]
    # "G3349PRDL000002" [...]

This works with single values, lists, and multiple path parameters:

result = client.call_rest_endpoint(
    endpoint="/hr/v2/workers/{associateOID}/jobs/{jobId}",
    associateOID="G3349PRDL000001",
    jobId="J42",
    inject_path_params=True,
)
# result[0]["associateOID"] == "G3349PRDL000001"
# result[0]["jobId"] == "J42"

Configure Logging

Enable logging to see token refresh events, pagination progress, and request errors:

from adpapi.logger import configure_logging

configure_logging()  # logs to console and a rotating file by default

Configure Retry Behavior

Customize which HTTP status codes trigger automatic retries:

from adpapi import AdpApiClient, AdpCredentials

credentials = AdpCredentials.from_env()

# Default retries on [429, 500, 502, 503, 504]
client = AdpApiClient(credentials)

# Custom retry status codes
client = AdpApiClient(
    credentials,
    retry_on_statuses=[429, 503]  # Only retry on rate limits and service unavailable
)

# Disable retries entirely
client = AdpApiClient(credentials, retry_on_statuses=[])

Manage Sessions

ApiSession is used internally by AdpApiClient — you don't need to interact with it directly. It handles connection pooling, certificate attachment, and header generation on every request. See the Concepts page for more detail.