Skip to content

Zenefits

Overview

Zenefits, now part of TriNet, is an all-in-one HR platform designed for small and medium businesses. While they offer comprehensive HR, benefits, payroll, and compliance features, their API access is restricted and requires approval, making integration more challenging than modern alternatives.

Platform Evolution

  • Original: Zenefits standalone platform
  • Current: TriNet Zenefits (acquired 2022)
  • Focus: SMB market (10-500 employees)
  • Strength: Benefits administration

Integration Challenges

  • Restricted API: Approval process required
  • Long Wait Times: Weeks to months for keys
  • Limited Documentation: Sparse public docs
  • Business Development: Partnership often required

API Access Process

The Reality of Zenefits API Access

Getting API access to Zenefits is not straightforward:

  1. Initial Application

    • Email developer support for access request
    • Provide detailed business case
    • Wait for initial response (1-2 weeks typical)
  2. Technical Review

    • Submit technical documentation
    • Prove integration capabilities
    • Pass security assessment
  3. Business Development

    • Often requires partnership discussion
    • Revenue sharing agreements may apply
    • Marketing commitments possible
  4. Approval & Credentials

    • If approved, receive sandbox access first
    • Production keys after successful testing
    • Total timeline: 4-12 weeks typically

Contact for API Access

To: [Contact Zenefits/TriNet developer support]
Subject: API Access Request - Tallyfy Integration
Dear Zenefits Developer Team,
We would like to request API access to integrate Tallyfy with Zenefits.
Company: [Your Company Name]
Use Case: Workflow automation for HR processes
Expected Volume: [Number of customers]
Technical Contact: [Your email]
Integration Type: [Direct API / Marketplace]
Please provide information on:
1. API access requirements
2. Technical documentation
3. Sandbox environment availability
4. Partnership requirements
Thank you,
[Your Name]

Alternative Integration Approaches

Given the challenges with direct API access, consider these alternatives:

Why Unified APIs Work Better

// Example: Using Finch for Zenefits data
const Finch = require('@finch-hq/client');
const finch = new Finch({
apiKey: 'your_finch_api_key' // Get this in days, not months
});
// Access Zenefits data immediately
const getZenefitsEmployees = async (accessToken) => {
const employees = await finch.hris.directory.list({
accessToken: accessToken // Customer's Zenefits connection
});
return employees.individuals.map(emp => ({
id: emp.id,
name: `${emp.first_name} ${emp.last_name}`,
email: emp.emails?.[0]?.data,
department: emp.department?.name,
manager: emp.manager?.id
}));
};

Benefits:

  • API keys in days, not months
  • No partnership requirements
  • Standardized data models
  • Multiple HRIS with one integration

2. Browser Automation (Last Resort)

# Example: Puppeteer automation for Zenefits
from playwright.sync_api import sync_playwright
import json
class ZenefitsAutomation:
def __init__(self, username, password):
self.username = username
self.password = password
def extract_employee_data(self):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Login to Zenefits
page.goto('https://secure.zenefits.com/accounts/login/')
page.fill('#username', self.username)
page.fill('#password', self.password)
page.click('button[type="submit"]')
# Wait for dashboard
page.wait_for_selector('.dashboard', timeout=10000)
# Navigate to employees
page.click('a[href*="/people/directory"]')
page.wait_for_selector('.employee-list')
# Extract data
employees = page.evaluate('''
() => {
const rows = document.querySelectorAll('.employee-row');
return Array.from(rows).map(row => ({
name: row.querySelector('.name')?.textContent,
email: row.querySelector('.email')?.textContent,
department: row.querySelector('.department')?.textContent,
status: row.querySelector('.status')?.textContent
}));
}
''')
browser.close()
return employees

3. File-Based Integration

Many Zenefits customers resort to scheduled exports:

// Process Zenefits CSV exports
const processZenefitsExport = async (csvPath) => {
const csv = require('csv-parser');
const fs = require('fs');
const employees = [];
fs.createReadStream(csvPath)
.pipe(csv())
.on('data', (row) => {
employees.push({
employeeId: row['Employee ID'],
name: row['Full Name'],
email: row['Work Email'],
department: row['Department'],
manager: row['Manager'],
hireDate: row['Hire Date'],
status: row['Employment Status']
});
})
.on('end', async () => {
// Process employees in Tallyfy
for (const employee of employees) {
if (employee.status === 'Active' && isNewHire(employee.hireDate)) {
await createOnboardingProcess(employee);
}
}
});
};
// Schedule daily import
const cron = require('node-cron');
cron.schedule('0 9 * * *', () => {
const today = new Date().toISOString().split('T')[0];
const exportPath = `/imports/zenefits_${today}.csv`;
if (fs.existsSync(exportPath)) {
processZenefitsExport(exportPath);
}
});

If You Get API Access

OAuth 2.0 Implementation

// Zenefits OAuth flow
class ZenefitsOAuth {
constructor(clientId, clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.baseUrl = 'https://secure.zenefits.com';
}
getAuthorizationUrl(redirectUri, state) {
const params = new URLSearchParams({
response_type: 'code',
client_id: this.clientId,
redirect_uri: redirectUri,
scope: 'read write',
state: state
});
return `${this.baseUrl}/oauth/authorize?${params}`;
}
async exchangeCodeForToken(code, redirectUri) {
const response = await fetch(`${this.baseUrl}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'authorization_code',
code: code,
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: redirectUri
})
});
return response.json();
}
async refreshToken(refreshToken) {
const response = await fetch(`${this.baseUrl}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret
})
});
return response.json();
}
}

API Endpoints (When Available)

// Common Zenefits API operations
class ZenefitsAPI {
constructor(accessToken) {
this.accessToken = accessToken;
this.baseUrl = 'https://api.zenefits.com/v1';
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
throw new Error(`Zenefits API error: ${response.statusText}`);
}
return response.json();
}
// Get all employees
async getEmployees(limit = 100) {
return this.request('/employees', {
method: 'GET',
params: { limit }
});
}
// Get specific employee
async getEmployee(employeeId) {
return this.request(`/employees/${employeeId}`);
}
// Get time off requests
async getTimeOffRequests() {
return this.request('/time_off_requests');
}
// Get benefits enrollments
async getBenefitsEnrollments() {
return this.request('/benefits/enrollments');
}
}

Pagination Handling

// Handle Zenefits pagination
async function getAllRecords(api, endpoint) {
const allRecords = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await api.request(endpoint, {
params: {
limit: 100,
page: page
}
});
allRecords.push(...response.data);
// Check if more pages exist
hasMore = response.has_more || false;
page++;
// Respect rate limits
await sleep(100);
}
return allRecords;
}

Common Integration Patterns

Benefits Enrollment Automation

// Monitor benefits enrollment periods
class BenefitsEnrollmentAutomation {
async checkEnrollmentStatus() {
// Get all employees
const employees = await this.zenefits.getEmployees();
for (const employee of employees) {
// Check enrollment window
if (this.isInEnrollmentWindow(employee)) {
// Create Tallyfy process
await this.tallyfy.createProcess({
template: 'benefits-enrollment',
data: {
employeeId: employee.id,
employeeName: employee.full_name,
enrollmentDeadline: employee.enrollment_deadline,
currentBenefits: employee.current_benefits,
eligiblePlans: await this.getEligiblePlans(employee)
}
});
}
}
}
isInEnrollmentWindow(employee) {
const today = new Date();
const windowStart = new Date(employee.enrollment_start);
const windowEnd = new Date(employee.enrollment_end);
return today >= windowStart && today <= windowEnd;
}
async getEligiblePlans(employee) {
// Fetch available benefit plans for employee
return this.zenefits.request(`/benefits/eligible_plans?employee_id=${employee.id}`);
}
}

Time-Off Management

// Sync time-off requests with approval workflows
const syncTimeOffRequests = async () => {
const requests = await zenefits.getTimeOffRequests();
for (const request of requests) {
if (request.status === 'pending') {
// Check if process exists
const existing = await tallyfy.findProcess({
externalId: `zenefits_pto_${request.id}`
});
if (!existing) {
// Create approval workflow
await tallyfy.createProcess({
template: 'pto-approval',
externalId: `zenefits_pto_${request.id}`,
data: {
requestId: request.id,
employee: request.employee_name,
type: request.time_off_type,
startDate: request.start_date,
endDate: request.end_date,
days: request.days_requested,
manager: request.approver_name,
reason: request.reason
}
});
}
}
}
};
// Handle approval decisions
tallyfy.on('process.completed', async (process) => {
if (process.template === 'pto-approval') {
const decision = process.outcome;
const requestId = process.data.requestId;
if (decision === 'approved') {
await zenefits.approveTimeOff(requestId);
} else {
await zenefits.denyTimeOff(requestId, process.data.denialReason);
}
}
});

Compliance and Security

Data Handling Best Practices

// Secure storage of sensitive data
class SecureZenefitsIntegration {
constructor() {
// Encrypt tokens at rest
this.tokenStorage = new EncryptedStorage();
// Audit all API calls
this.auditLog = new AuditLogger();
}
async makeSecureRequest(endpoint, method, data) {
const startTime = Date.now();
try {
// Log request (without sensitive data)
await this.auditLog.log({
action: 'zenefits_api_call',
endpoint: endpoint,
method: method,
timestamp: new Date().toISOString()
});
// Make request
const response = await this.zenefits.request(endpoint, {
method,
body: data
});
// Log success
await this.auditLog.log({
action: 'zenefits_api_success',
endpoint: endpoint,
duration: Date.now() - startTime
});
return response;
} catch (error) {
// Log failure
await this.auditLog.log({
action: 'zenefits_api_error',
endpoint: endpoint,
error: error.message,
duration: Date.now() - startTime
});
throw error;
}
}
}

Migration Path from Zenefits

If considering migration:

  1. Export Data

    • Employee records
    • Benefits enrollment
    • Time-off balances
    • Payroll history
  2. Choose New Platform

    • Evaluate API capabilities
    • Check integration ecosystem
    • Verify feature parity
  3. Run Parallel

    • Keep Zenefits active during transition
    • Sync data between systems
    • Validate accuracy
  4. Cut Over

    • Move primary operations
    • Archive Zenefits data
    • Update integrations

Support Resources

Getting Help

  • TriNet Support: Primary support channel
  • Legacy Zenefits Docs: May still be available
  • Unified API Providers: Often have better docs
  • Community Forums: Limited but sometimes helpful

Conclusion

Zenefits (now TriNet Zenefits) presents significant integration challenges due to restricted API access and lengthy approval processes. For most organizations, using a unified API provider like Finch or Merge offers a much faster path to integration. If you must integrate directly with Zenefits, be prepared for a multi-month process and consider file-based integration as an interim solution.

Vendors > TriNet

Tallyfy integrates with TriNet to automatically transform PEO data into orchestrated business workflows that handle employee onboarding compliance tracking and operational processes while eliminating manual coordination between HR systems and business operations.

Vendors > Namely

Namely is an all-in-one HR platform for mid-market companies that offers robust API access through partnership programs and provides comprehensive employee management capabilities with webhook support for real-time workflow automation.

Vendors > NetSuite

Tallyfy integrates with NetSuite SuitePeople to transform unified business data into automated workflows spanning HR finance and operations while maintaining NetSuite as your single source of truth.

Vendors > Insperity

Insperity is a leading PEO that provides comprehensive HR outsourcing services for SMBs but offers limited integration capabilities with no public API access requiring creative workarounds like file-based data exchange and browser automation to connect with external systems like Tallyfy.