Introduction
If you're building an HR data pipeline, automating payroll syncs, or powering internal dashboards, UKG Pro (UKG HRIS) is one of the more sophisticated HRIS platforms you'll encounter. This guide breaks down, how to retrieve employee data from the UKG HRIS API.
It’s part of a larger deep-dive series unpacking HRIS authentication, rate limits, scopes, and best practices. You can explore the full guide here.
How to Get Employee Data from the UKG HRIS API
Prerequisites
Before you begin, make sure you have the following:
- A UKG Pro Service Account — a dedicated API service account in your UKG Pro environment (not a regular employee login). Created in UKG Pro under Administration → Security → Service Account Administration.
- Customer API Key — assigned to your UKG Pro company environment. Found in UKG Pro under Administration → System Configuration → Security → Service Account Administration.
- User API Key (ClientAccessKey) — assigned to the specific service account user. Different from the Customer API Key.
- Service Account Username and Password — the credentials for the service account.
- Your company-specific UKG Pro hostname — assigned by UKG during onboarding. Not a generic URL. Format is typically
service2.ultipro.com,service5.ultipro.com, oryourcompany.ultipro.com. If you're unsure of your hostname, check with your UKG Pro administrator or UKG Support. - Python 3.x with the
requestslibrary installed (pip install requests)
Key API Endpoints
Note:api.ukg.com is not the base URL for UKG Pro HCM. Every UKG Pro company gets a dedicated hostname. Using the wrong hostname will result in a 404 or connection error, not an auth error.Step-by-Step Guide
Step 1: Authenticate and Get a Token
UKG Pro HCM uses a token-based authentication flow that requires three separate credentials: a Customer API Key (per company), a User API Key (per service account), and the service account's username and password. All four are required.
import requests
# Your company-specific UKG Pro hostname — NOT api.ukg.com
# Example: "service2.ultipro.com" or "yourcompany.ultipro.com"
HOSTNAME = "your-company.ultipro.com"
CUSTOMER_API_KEY = "your_customer_api_key"
USER_API_KEY = "your_user_api_key" # Also called ClientAccessKey
auth_url = f"https://{HOSTNAME}/authentication/login"
auth_headers = {
"US-Customer-Api-Key": CUSTOMER_API_KEY,
"Content-Type": "application/json"
}
auth_body = {
"UserName": "service_account@yourcompany.com",
"Password": "your_service_account_password",
"ClientAccessKey": USER_API_KEY
}
try:
response = requests.post(auth_url, json=auth_body, headers=auth_headers)
response.raise_for_status()
token = response.json().get("access_token")
if not token:
raise ValueError("Authentication succeeded but no access_token returned")
except requests.HTTPError as e:
print(f"Auth failed: {e.response.status_code} — {e.response.text}")
raiseImportant: The US-Customer-Api-Key header is required on the authentication call itself, not just on subsequent requests. Without it, the auth call will return 401 even with valid credentials.
Token format: Unlike standard OAuth, UKG Pro tokens are used WITHOUT a Bearer prefix. See Step 2 for the correct header format.
2. Fetch One Employee’s Data
def get_employee(employee_id: str, token: str, hostname: str, customer_api_key: str) -> dict:
"""
Retrieve a single employee record from UKG Pro.
Args:
employee_id: The UKG Pro internal employee ID (not the employee number)
token: Bearer token from the authentication step
hostname: Your UKG Pro hostname
customer_api_key: Your Customer API Key
Returns:
Employee record as a dict
"""
url = f"https://{hostname}/personnel/v1/employees/{employee_id}"
headers = {
"Authorization": token, # No "Bearer" prefix — raw token
"US-Customer-Api-Key": customer_api_key,
"Content-Type": "application/json"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.HTTPError as e:
if e.response.status_code == 401:
print("Token expired or invalid — re-authenticate and retry")
print(f"Error fetching employee {employee_id}: {e.response.status_code}")
raise
# Usage
employee = get_employee(
employee_id="12345",
token=token,
hostname=HOSTNAME,
customer_api_key=CUSTOMER_API_KEY
)
print(employee)Critical: The Authorization header value is the raw token string — no "Bearer " prefix. UKG Pro's auth scheme is not standard OAuth Bearer. Prepending Bearer will result in a 401 on every call.
The US-Customer-Api-Key header must be included on every API call, not just the auth call.
3. Fetch All Employees’ Data
UKG Pro paginates employee responses. A bare call to /personnel/v1/employees returns only the first page. For any production use, implement pagination from the start.
def get_all_employees(token: str, hostname: str, customer_api_key: str, per_page: int = 100) -> list:
"""
Retrieve all employees from UKG Pro with automatic pagination.
Args:
token: Access token from authentication
hostname: Your UKG Pro hostname
customer_api_key: Your Customer API Key
per_page: Number of records per page (max typically 100)
Returns:
List of all employee records
"""
url = f"https://{hostname}/personnel/v1/employees"
headers = {
"Authorization": token,
"US-Customer-Api-Key": customer_api_key,
"Content-Type": "application/json"
}
all_employees = []
page = 1
while True:
params = {
"page": page,
"per_page": per_page
}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
batch = response.json()
except requests.HTTPError as e:
print(f"Error on page {page}: {e.response.status_code} — {e.response.text}")
raise
if not batch:
break
all_employees.extend(batch)
print(f"Fetched page {page}: {len(batch)} records (total so far: {len(all_employees)})")
# If we got fewer records than requested, we've hit the last page
if len(batch) < per_page:
break
page += 1
return all_employees
# Usage
employees = get_all_employees(
token=token,
hostname=HOSTNAME,
customer_api_key=CUSTOMER_API_KEY
)
print(f"Total employees fetched: {len(employees)}")For large employee populations (5,000+), consider adding a small delay between pages (time.sleep(0.5)) to stay within UKG Pro's rate limits.
Common Pitfalls (and How to Avoid Them)
1. Using the wrong hostname or base URL -The most common first-attempt failure. api.ukg.com is not the base URL for UKG Pro HCM. Your hostname is company-specific and provided by UKG during onboarding. If you're not sure, check with your UKG Pro administrator — it's usually in the URL when you log in to UKG Pro in a browser.
2. Missing the US-Customer-Api-Key header - This header must be present on every single call — both the authentication call and all subsequent API calls. Omitting it on data calls returns 401 even with a valid token.
3. Prepending "Bearer" to the Authorization token - UKG Pro tokens are not standard OAuth Bearer tokens. The Authorization header value should be the raw token string. Authorization: Bearer {token} will fail; Authorization: {token} is correct.
4. Token expiry with no refresh logic - UKG Pro tokens expire (typically after a few hours). For long-running jobs or scheduled processes, add logic to detect 401 responses and re-authenticate. Do not cache tokens across days.
5. No pagination on employee fetches - UKG Pro paginates by default. A call to /personnel/v1/employees without page parameters returns only the first page — usually 25–100 records. Any production integration that pulls all employees must implement the pagination loop shown in Step 3.
6. Deeply nested JSON structures - UKG Pro employee records are complex. Fields like employment status, pay rates, and job assignments are nested multiple levels deep. Map the full schema before building your data pipeline — do not assume a flat structure.
7. Inconsistent field population across customers - Certain optional fields are only populated if the UKG Pro administrator has configured them. Build defensively: use .get() for all field access and define defaults for missing values.
8. Version changes breaking integrations - UKG does not always maintain backward compatibility across API versions. Pin to a specific version in your endpoint paths (/v1/) and monitor UKG's release notes for your tenant version.
Handling Token Refresh
For any integration that runs continuously or on a schedule, implement token refresh:
import time
class UKGProClient:
def __init__(self, hostname, customer_api_key, user_api_key, username, password):
self.hostname = hostname
self.customer_api_key = customer_api_key
self.user_api_key = user_api_key
self.username = username
self.password = password
self.token = None
self.token_fetched_at = None
self.token_ttl_seconds = 3600 # Adjust to match your UKG Pro token expiry
def _needs_refresh(self):
if not self.token or not self.token_fetched_at:
return True
return (time.time() - self.token_fetched_at) > (self.token_ttl_seconds - 60)
def get_token(self):
if self._needs_refresh():
auth_url = f"https://{self.hostname}/authentication/login"
response = requests.post(
auth_url,
json={
"UserName": self.username,
"Password": self.password,
"ClientAccessKey": self.user_api_key
},
headers={
"US-Customer-Api-Key": self.customer_api_key,
"Content-Type": "application/json"
}
)
response.raise_for_status()
self.token = response.json()["access_token"]
self.token_fetched_at = time.time()
return self.token
def get_headers(self):
return {
"Authorization": self.get_token(),
"US-Customer-Api-Key": self.customer_api_key,
"Content-Type": "application/json"
}FAQs
What credentials do I need to call the UKG Pro API?
UKG Pro requires four pieces of information: a Customer API Key (assigned to your company environment), a User API Key (assigned to your service account, also called ClientAccessKey), a service account username, and the service account password. You also need your company-specific hostname — a generic base URL like api.ukg.com does not apply to UKG Pro HCM. All four credentials are required on every authentication call.
Why is my UKG Pro authentication returning 401 even with correct credentials?
The most common cause is a missing US-Customer-Api-Key header on the auth call. This header is required on the login request itself, not just on subsequent data calls. The second most common cause is using the wrong hostname — verify that you are using your company-specific UKG Pro hostname rather than a generic URL. Third: check that your service account has Web Services permissions enabled in UKG Pro Administration.
Does UKG Pro use Bearer tokens?
No. UKG Pro's core HCM REST APIs use a token-based scheme where the token is sent as the raw Authorization header value — without the Bearer prefix. Authorization: {token} is correct; Authorization: Bearer {token} will return 401 on all data calls. This is different from standard OAuth 2.0 behavior.
How do I paginate through all employee records?
UKG Pro uses page and per_page query parameters. Start with ?page=1&per_page=100 and increment page until the response returns fewer records than per_page. Do not call the endpoint without pagination parameters in production — you will only receive the first page of results, with no indication that more exist.
What is the difference between the UKG Pro API and the UKG Ready API?
UKG Pro is the enterprise HCM platform (formerly UltiPro) with people, payroll, benefits, and talent modules. Its API uses tenant-specific hostnames and the authentication flow described in this guide. UKG Ready (formerly Kronos Workforce Ready) is a separate product for SMB workforce management with a completely different API hosted at secure7.saashr.com. The two products have different endpoints, different authentication flows, and different data models — integrations built for one will not work for the other.
What are the rate limits for the UKG Pro API?
Rate limits are configured per UKG Pro environment and are not published as universal figures — they depend on your contract and tenant configuration. Check your UKG Pro environment documentation or contact UKG Support for your specific limits. Practically, batch your calls, implement pagination at reasonable page sizes (25–100 records), and add a short delay between pages for large data pulls.
Does UKG Pro support webhooks for employee data changes?
Yes. UKG has introduced webhooks through the UKG Webhooks Premium feature (available on the UKG Pro Platform). This lets you subscribe to change events rather than polling the employees endpoint on a schedule. For teams that need near-real-time sync without polling overhead, webhooks are the right architectural choice. See the UKG Developer Hub (developer.ukg.com/proplatform/docs/welcome-to-ukg-webhooks) for setup details.
Does UKG Pro have a sandbox environment?
Yes. Sandbox access must be requested through UKG Support. Your sandbox environment will have a separate hostname and separate credentials from your production environment. Always test new integrations and version updates in sandbox before running against production data.
Monitor UKG’s release notes and test your integration in a sandbox during upgrades.
Knit: The Faster Way to Integrate with UKG HRIS API
If you're building a product that needs to integrate with UKG Pro or UKG Ready (and likely other HRIS platforms — Workday, BambooHR, Darwinbox, ADP, HiBob), Knit gives you a single normalized API for all of them.
Instead of managing four separate UKG credentials, tenant-specific hostnames, token refresh logic, pagination, and API version changes for each platform you support, you integrate once with Knit. Knit handles authentication, token management, data normalization, rate limit handling, and API maintenance across 160+ HRIS, ATS, CRM, and accounting platforms.
For UKG specifically, Knit supports UKG Pro and UKG Ready through the same unified API interface — the same code that reads BambooHR employee data reads UKG data without modification.
For AI use cases, Knit MCP Servers give AI agents direct access to UKG employee data through the Model Context Protocol — no API integration code required.
Get started with Knit or book a demo.


%20(3).png)
.webp)
.webp)
