Skip to main content

External Integration

Payroll Partner

Two patterns are supported.

Push (Webhook)

Nightly job at 04:00 UTC posts locked days to the partner's endpoint:

POST https://payroll.partner/attendance/daily
Authorization: Bearer <partner-token>
Content-Type: application/json

[
{
"employee_id": "E123",
"organization_code": "ACME",
"unit_code": "ACME-BLR-01",
"date": "2026-04-01",
"status": "present",
"check_in": "09:05:00Z",
"check_out": "17:55:00Z",
"worked_minutes": 530,
"flags": ["LATE_CHECK_IN"]
}
]

Pull

Partner polls /integrations/payroll/pull:

GET /api/v1/integrations/payroll/pull?month=2026-04&org_id=1
Authorization: Bearer <partner-token>

Returns the full locked month or 409 LOCK_PENDING if the month isn't locked yet.

Billing

Billing systems receive the same payload as payroll. The billing-specific fields (rate_id, billable_minutes) live in the partner system, not here.

Webhook Signatures

Every webhook we send includes:

X-Attendance-Signature: t=1713870000,v1=3a7b...

Calculated as HMAC-SHA256(secret, "<timestamp>." + body). Partners must verify within a 5-minute window to prevent replay.

Rate Limits on Integration Endpoints

  • Pull: 60 req/min per partner.
  • Webhook retries: exponential backoff, 5 attempts, Retry-After respected.