Skip to content

ADP API Client Documentation

Welcome to the ADP API Client documentation. This project provides a Python client for interacting with the ADP Workforce Now API using OAuth 2.0 with certificate-based authentication.

NOTE: This project is not formally associated with the ADP API Client Central. Rather, it is an open-source SDK for users of the ADP API service.

Key Features

  • OAuth 2.0 client credentials authentication with certificate support
  • Automatic token management and refresh
  • Built-in retry logic with exponential backoff
  • Paginated OData queries via call_endpoint
  • Direct REST calls with path parameter substitution via call_rest_endpoint
  • Parallel batch requests via max_workers for up to ~10x throughput improvement
  • Comprehensive logging for debugging

Use Case

Without the AdpApi module, handling paginated API responses from ADP and token generation is extremely verbose.

Take, for example, the following code that handles exactly one request to the /hr/v2/workers endpoint, without pagination, token refreshing, or OData filtering

import json
import logging
import os
import time

import requests
from dotenv import load_dotenv

logger = logging.getLogger(__name__)
load_dotenv()

DEFAULT_TIMEOUT = 30
BASE_URL = "https://api.adp.com"
ENDPOINT = "/hr/v2/workers"

url = BASE_URL + ENDPOINT

# Read required ADP OAuth client credentials from environment.
client_id = os.environ['CLIENT_ID']
client_secret = os.environ['CLIENT_SECRET']
cert_path = 'certificate.pem'
key_path = 'adp.key'
cert = (cert_path, key_path)

def get_token(timeout: int = DEFAULT_TIMEOUT) -> str:
    logger.debug("Requesting Token from ADP Accounts endpoint")

    token_payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_secret": client_secret,
    }

    TOKEN_URL = "https://accounts.adp.com/auth/oauth/v2/token"
    try:
        response = requests.post(
            TOKEN_URL,
            data=token_payload,
            cert=cert,
            timeout=timeout,
        )

        response.raise_for_status()
        token_json = response.json()
        token = token_json.get("access_token")
        if not token:
            raise ValueError("No access token in response")

        # Track token expiration
        expires_in = token_json.get("expires_in", 3600)  # Default 1 hour
        logger.info(f"Token Acquired (expires in {expires_in}s)")
        return token
    except requests.RequestException as e:
        logger.error(f"Token request failed: {e}")
        raise

token = get_token()
params = {
    '$top': 1,
    '$skip': 0,
    '$select': 'workers/person/birthDate'
}
headers = {
    'Accept': 'application/json;masked=false',
    'Authorization': f'Bearer {token}' 
}

response = requests.get(
    url, params = params, headers = headers, cert = cert, timeout = DEFAULT_TIMEOUT
)

results = response.json()
print(results)

The adpapi turns this whole chunk of code into a simple, readable OOP approach that automatically handles token acquisition and parameter generation:

from dotenv import load_dotenv
from adpapi.client import AdpApiClient, AdpCredentials

load_dotenv()
credentials = AdpCredentials.from_env()
endpoint = '/hr/v2/workers'

with AdpApiClient(credentials) as api:
    results = api.call_endpoint(endpoint, select=['workers/person/birthDate'], page_size=1, max_requests=1)

print(results)