Integration Examples
Real-world examples of payroll reporting and employee sync with Audit1
Integration Examples
Complete, production-ready code examples for submitting payroll data, syncing employees, and handling webhook events.
🚀 Quick Start Examples
1. Submit Payroll (cURL)
Copy-paste ready example:
export AUDIT1_API_KEY="audit1_test_sk_your_key_here"
curl -X POST https://api.audit1.info/api/v1/payroll/reports \
-H "Authorization: Bearer $AUDIT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employer_id": "EMP_12345",
"period_start": "2024-01-01",
"period_end": "2024-03-31",
"employees": [
{
"employee_id": "EE_001",
"name": "John Smith",
"classification_code": "8810",
"hours_worked": 520,
"gross_wages": 26000
}
],
"payroll_data": {
"total_payroll": 26000,
"total_hours": 520,
"officer_payroll": 0,
"subcontractor_payments": 0
}
}'2. Sync Employee (cURL)
curl -X POST https://api.audit1.info/api/v1/employees/sync \
-H "Authorization: Bearer $AUDIT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employer_id": "EMP_12345",
"employees": [
{
"employee_id": "EE_NEW_001",
"action": "hire",
"name": "Jane Doe",
"hire_date": "2024-01-15",
"classification_code": "8810",
"hourly_rate": 30.00
}
]
}'3. Check File Status (cURL)
curl -X GET https://api.audit1.info/api/v1/files/status/FILE_123 \
-H "Authorization: Bearer $AUDIT1_API_KEY"Complete Working Examples
Submit Quarterly Payroll Report
curl -X POST https://api.audit1.info/api/v1/payroll/reports \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employer_id": "EMP_12345",
"period_start": "2024-01-01",
"period_end": "2024-03-31",
"employees": [
{
"employee_id": "EE_001",
"name": "John Smith",
"classification_code": "8810",
"hours_worked": 520,
"gross_wages": 26000,
"overtime_hours": 20,
"overtime_pay": 1500
},
{
"employee_id": "EE_002",
"name": "Jane Doe",
"classification_code": "5403",
"hours_worked": 480,
"gross_wages": 38400
}
],
"payroll_data": {
"total_payroll": 64400,
"total_hours": 1000,
"officer_payroll": 0,
"subcontractor_payments": 0
}
}'Response:
{
"message": "Payroll report submitted successfully",
"report_id": "PR_1705932000123",
"status": "processing",
"employee_count": 2,
"estimated_processing_time": "5-10 minutes"
}Node.js Example
Production-Ready Implementation
const axios = require('axios');
// Configure client with retry logic
class Audit1Client {
constructor(apiKey) {
this.client = axios.create({
baseURL: 'https://api.audit1.info/api/v1',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
timeout: 30000 // 30 second timeout
});
}
async submitPayrollReport(employerId, periodStart, periodEnd, employees) {
// Validate inputs
if (!employerId || !periodStart || !periodEnd || !employees?.length) {
throw new Error('Missing required parameters');
}
// Calculate totals
const payrollData = {
total_payroll: employees.reduce((sum, e) => sum + (e.gross_wages || 0), 0),
total_hours: employees.reduce((sum, e) => sum + (e.hours_worked || 0), 0),
officer_payroll: employees
.filter(e => e.is_officer)
.reduce((sum, e) => sum + (e.gross_wages || 0), 0),
subcontractor_payments: 0
};
const payload = {
employer_id: employerId,
period_start: periodStart,
period_end: periodEnd,
employees: employees,
payroll_data: payrollData
};
try {
const response = await this.retryRequest(() =>
this.client.post('/payroll/reports', payload)
);
console.log('Payroll report submitted:', {
report_id: response.data.report_id,
status: response.data.status,
environment: response.data.environment,
employee_count: response.data.employee_count
});
return response.data;
} catch (error) {
console.error('Failed to submit payroll:', {
error: error.message,
status: error.response?.status,
details: error.response?.data
});
throw error;
}
}
async retryRequest(fn, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
// Don't retry client errors (except rate limits)
const status = error.response?.status;
if (status >= 400 && status < 500 && status !== 429) {
throw error;
}
// Calculate exponential backoff
const backoffMs = Math.min(Math.pow(2, i) * 1000, 30000);
console.log(`Retry ${i + 1}/${maxRetries} after ${backoffMs}ms`);
await new Promise(resolve => setTimeout(resolve, backoffMs));
}
}
throw lastError;
}
}
// Usage Example
const client = new Audit1Client(process.env.AUDIT1_API_KEY);
const employees = [
{
employee_id: 'EE_001',
name: 'John Smith',
classification_code: '8810',
hours_worked: 520,
gross_wages: 26000,
overtime_hours: 20,
overtime_pay: 1500
},
{
employee_id: 'EE_002',
name: 'Jane Doe',
classification_code: '5403',
hours_worked: 480,
gross_wages: 38400,
is_officer: true
}
];
// Submit payroll
client.submitPayrollReport(
'EMP_12345',
'2024-01-01',
'2024-03-31',
employees
).then(result => {
console.log('Success:', result.report_id);
}).catch(error => {
console.error('Failed:', error.message);
process.exit(1);
});Environment Configuration
// config.js
module.exports = {
development: {
apiKey: process.env.AUDIT1_TEST_KEY,
environment: 'sandbox'
},
production: {
apiKey: process.env.AUDIT1_LIVE_KEY,
environment: 'production'
}
};
// app.js
const config = require('./config');
const env = process.env.NODE_ENV || 'development';
const client = new Audit1Client(config[env].apiKey);Python Example
Production-Ready Implementation
import os
import time
import requests
from typing import List, Dict, Optional
from datetime import datetime
class Audit1Client:
def __init__(self, api_key: str):
self.base_url = 'https://api.audit1.info/api/v1'
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
self.session = requests.Session()
self.session.headers.update(self.headers)
def submit_payroll_report(
self,
employer_id: str,
period_start: str,
period_end: str,
employees: List[Dict]
) -> Dict:
"""Submit payroll report with automatic retry logic."""
# Calculate totals
total_payroll = sum(e.get('gross_wages', 0) for e in employees)
total_hours = sum(e.get('hours_worked', 0) for e in employees)
officer_payroll = sum(
e.get('gross_wages', 0)
for e in employees
if e.get('is_officer', False)
)
payload = {
'employer_id': employer_id,
'period_start': period_start,
'period_end': period_end,
'employees': employees,
'payroll_data': {
'total_payroll': total_payroll,
'total_hours': total_hours,
'officer_payroll': officer_payroll,
'subcontractor_payments': 0
}
}
return self._retry_request(
lambda: self.session.post(
f'{self.base_url}/payroll/reports',
json=payload
)
)
def _retry_request(self, fn, max_retries: int = 3) -> Dict:
"""Execute request with exponential backoff retry."""
last_error = None
for attempt in range(max_retries):
try:
response = fn()
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
last_error = e
status = e.response.status_code
# Don't retry client errors (except rate limits)
if 400 <= status < 500 and status != 429:
raise
# Calculate backoff
backoff = min(2 ** attempt, 30)
print(f'Retry {attempt + 1}/{max_retries} after {backoff}s')
time.sleep(backoff)
raise last_error
# Usage
if __name__ == '__main__':
client = Audit1Client(os.getenv('AUDIT1_API_KEY'))
employees = [
{
'employee_id': 'EE_001',
'name': 'John Smith',
'classification_code': '8810',
'hours_worked': 520,
'gross_wages': 26000
}
]
try:
result = client.submit_payroll_report(
employer_id='EMP_12345',
period_start='2024-01-01',
period_end='2024-03-31',
employees=employees
)
print(f"Success: {result['report_id']}")
except Exception as e:
print(f"Failed: {str(e)}")
exit(1)Common Integration Patterns
Pattern 1: Batch Processing
// Process payroll reports in batches
async function processBatchPayroll(reports, batchSize = 10) {
const results = [];
for (let i = 0; i < reports.length; i += batchSize) {
const batch = reports.slice(i, i + batchSize);
// Process batch in parallel
const batchResults = await Promise.allSettled(
batch.map(report => client.submitPayrollReport(
report.employer_id,
report.period_start,
report.period_end,
report.employees
))
);
results.push(...batchResults);
// Rate limit: wait between batches
if (i + batchSize < reports.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return results;
}Pattern 2: Webhook Verification
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express endpoint
app.post('/webhooks/audit1', (req, res) => {
const signature = req.headers['x-audit1-signature'];
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
console.log('Webhook received:', req.body.event_type);
res.status(200).json({ received: true });
});Pattern 3: Idempotency
// Track processed reports to prevent duplicates
const processedReports = new Set();
async function submitPayrollIdempotent(data) {
const idempotencyKey = `${data.employer_id}-${data.period_start}-${data.period_end}`;
if (processedReports.has(idempotencyKey)) {
console.log('Report already processed:', idempotencyKey);
return { skipped: true };
}
const result = await client.submitPayrollReport(
data.employer_id,
data.period_start,
data.period_end,
data.employees
);
processedReports.add(idempotencyKey);
return result;
}Node.js Example
const submitPayrollReport = async (employerId, periodStart, periodEnd, employees) => {
const apiKey = process.env.AUDIT1_API_KEY;
const payload = {
employer_id: employerId,
period_start: periodStart,
period_end: periodEnd,
employees: employees,
payroll_data: {
total_payroll: employees.reduce((sum, e) => sum + e.gross_wages, 0),
total_hours: employees.reduce((sum, e) => sum + e.hours_worked, 0),
officer_payroll: 0,
subcontractor_payments: 0
}
};
const response = await fetch('https://api.audit1.info/api/v1/payroll/reports', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return await response.json();
};
// Usage
const employees = [
{
employee_id: 'EE_001',
name: 'John Smith',
classification_code: '8810',
hours_worked: 520,
gross_wages: 26000
}
];
const result = await submitPayrollReport('EMP_12345', '2024-01-01', '2024-03-31', employees);
console.log('Report ID:', result.report_id);Python Example
import requests
import os
def submit_payroll_report(employer_id, period_start, period_end, employees):
api_key = os.environ['AUDIT1_API_KEY']
total_payroll = sum(e['gross_wages'] for e in employees)
total_hours = sum(e['hours_worked'] for e in employees)
payload = {
'employer_id': employer_id,
'period_start': period_start,
'period_end': period_end,
'employees': employees,
'payroll_data': {
'total_payroll': total_payroll,
'total_hours': total_hours,
'officer_payroll': 0,
'subcontractor_payments': 0
}
}
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
response = requests.post(
'https://api.audit1.info/api/v1/payroll/reports',
headers=headers,
json=payload
)
response.raise_for_status()
return response.json()
# Usage
employees = [
{
'employee_id': 'EE_001',
'name': 'John Smith',
'classification_code': '8810',
'hours_worked': 520,
'gross_wages': 26000
}
]
result = submit_payroll_report('EMP_12345', '2024-01-01', '2024-03-31', employees)
print(f"Report ID: {result['report_id']}")Sync Employee Changes
New Hire
curl -X POST https://api.audit1.info/api/v1/employees/sync \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employer_id": "EMP_12345",
"employees": [
{
"employee_id": "EE_NEW_003",
"action": "hire",
"name": "Alice Williams",
"hire_date": "2024-02-15",
"classification_code": "8810",
"hourly_rate": 28.50
}
]
}'Termination
curl -X POST https://api.audit1.info/api/v1/employees/sync \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employer_id": "EMP_12345",
"employees": [
{
"employee_id": "EE_002",
"action": "terminate",
"termination_date": "2024-03-31",
"reason": "voluntary"
}
]
}'Bulk Changes
const changes = [
{
employee_id: 'EE_NEW_004',
action: 'hire',
name: 'Charlie Brown',
hire_date: '2024-03-01',
classification_code: '5403',
hourly_rate: 45.00
},
{
employee_id: 'EE_001',
action: 'update',
hourly_rate: 32.00 // Wage increase
},
{
employee_id: 'EE_002',
action: 'terminate',
termination_date: '2024-03-15',
reason: 'retirement'
}
];
const response = await fetch('https://api.audit1.info/api/v1/employees/sync', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.AUDIT1_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
employer_id: 'EMP_12345',
employees: changes
})
});
const result = await response.json();
console.log('Sync ID:', result.sync_id);Check File Processing Status
curl -X GET https://api.audit1.info/api/v1/files/status/FILE_67890 \
-H "Authorization: Bearer YOUR_API_KEY"Response:
{
"file_id": "FILE_67890",
"status": "completed",
"uploaded_at": "2024-01-15T14:30:00Z",
"processed_at": "2024-01-15T14:35:22Z",
"records_total": 150,
"records_processed": 150,
"records_failed": 0,
"validation_errors": []
}Polling Implementation
const pollFileStatus = async (fileId, maxAttempts = 30) => {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.audit1.info/api/v1/files/status/${fileId}`,
{
headers: {
'Authorization': `Bearer ${process.env.AUDIT1_API_KEY}`
}
}
);
const status = await response.json();
if (status.status === 'completed') {
return status;
}
if (status.status === 'failed') {
throw new Error('File processing failed');
}
// Wait 10 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 10000));
}
throw new Error('Timeout waiting for file processing');
};Handle Webhook Events
Configure webhooks in your portal dashboard (Webhooks section) to receive events from Audit1.
Node.js/Express Webhook Handler
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/audit1', (req, res) => {
const { event, data } = req.body;
switch (event) {
case 'audit.completed':
console.log('Audit completed:', data.audit_id);
console.log('Premium:', data.premium_calculated);
break;
case 'payroll.processed':
console.log('Payroll processed:', data.report_id);
console.log('Records:', data.records_processed);
break;
case 'policy.updated':
console.log('Policy updated:', data.policy_id);
break;
}
// Respond quickly (< 5 seconds)
res.status(200).send('OK');
});
app.listen(3000);Example Webhook Payloads
audit.completed:
{
"event": "audit.completed",
"timestamp": "2024-01-15T16:45:30Z",
"data": {
"audit_id": "AUD_123456",
"employer_id": "EMP_12345",
"status": "completed",
"premium_calculated": 15234.50
}
}payroll.processed:
{
"event": "payroll.processed",
"timestamp": "2024-01-15T14:35:22Z",
"data": {
"report_id": "PR_1705932000123",
"employer_id": "EMP_12345",
"status": "completed",
"records_processed": 150,
"records_failed": 0
}
}Error Handling
Common Errors
400 Bad Request:
{
"error": "Missing required fields",
"required": ["employer_id", "period_start", "period_end", "employees", "payroll_data"]
}401 Unauthorized:
{
"error": "Unauthorized",
"message": "Invalid API key. Get yours from your portal dashboard (API Keys section)"
}Retry Logic
async function submitWithRetry(payload, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.audit1.info/api/v1/payroll/reports', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.AUDIT1_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (response.ok) {
return await response.json();
}
// Don't retry client errors
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client error: ${response.status}`);
}
// Retry server errors with backoff
console.log(`Attempt ${attempt} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
} catch (error) {
if (attempt === maxRetries) throw error;
}
}
}Best Practices
- Secure API Keys: Use environment variables, never commit to version control
- Test with Sandbox Keys: Use
audit1_test_sk_...keys for development (same URL, test data) - Validate Data: Check classification codes, wage amounts before submitting
- Handle Errors: Implement retry logic with exponential backoff
- Use Webhooks: Don't poll - configure webhooks for real-time events
Next Steps
- API Reference - Complete endpoint documentation
- Webhooks Guide - Set up event notifications
- API Keys Guide - Create and manage credentials
Need help? Email [email protected]
Updated 1 day ago
