Skip to main content
Manage pay periods for the client companies in your bookkeeper organization. All endpoints require an admin JWT and enforce tenant isolation: you can only touch pay periods whose company belongs to your bookkeeperOrgId.
MethodPathPurpose
GET/api/v1/admin/pay-periodsList pay periods (paginated)
POST/api/v1/admin/pay-periodsCreate a pay period
GET/api/v1/admin/pay-periods/{id}Get one pay period (with entries + totals)
PUT/api/v1/admin/pay-periods/{id}Update status / lock / pay date / export metadata
DELETE/api/v1/admin/pay-periods/{id}Delete a pay period (only if it has no time entries)

List pay periods

GET /api/v1/admin/pay-periods

Query parameters

companyId
string
Filter to one company. The company must belong to your organization, or the request returns 403. If omitted, all pay periods within your organization are returned.
status
string
Filter by status: OPEN, SUBMITTED, APPROVED, PAID, or CLOSED.
page
integer
default:"1"
pageSize
integer
default:"20"

Response

Paginated envelope (items, total, page, pageSize, totalPages), ordered by startDate descending. Each item includes its company (id, name) and a _count of timeEntries.
curl "https://app.paypunch.io/api/v1/admin/pay-periods?companyId=c9d8...&status=OPEN" \
  -H "Authorization: Bearer <admin-token>"

Create a pay period

POST /api/v1/admin/pay-periods

Request body

companyId
string
required
UUID of the client company. Must belong to your organization (403 otherwise, 404 if the company does not exist).
periodType
string
required
One of WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY.
startDate
string
required
ISO-8601 datetime or a YYYY-MM-DD date.
endDate
string
ISO-8601 datetime or YYYY-MM-DD. If omitted, it is computed from periodType and startDate.
payDate
string
ISO-8601 datetime or YYYY-MM-DD. Optional.
New pay periods are created with status: "OPEN" and locked: false. The server rejects date ranges that overlap an existing pay period for the same company with 400 Overlapping pay period.
curl -X POST https://app.paypunch.io/api/v1/admin/pay-periods \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "companyId": "c9d8...",
    "periodType": "BI_WEEKLY",
    "startDate": "2026-06-15",
    "payDate": "2026-07-03"
  }'

Get a pay period

GET /api/v1/admin/pay-periods/{id}
id
string
required
The pay period’s UUID.
Returns the pay period with its company, all timeEntries (each with a trimmed employee), and a computed totals object summing totalHours, regularHours, and overtimeHours. Returns 404 if not found, 403 if the period belongs to another organization.
Response (200)
{
  "success": true,
  "data": {
    "id": "pp_01...",
    "status": "OPEN",
    "company": { "id": "c9d8...", "name": "Builders R Us", "bookkeeperOrgId": "a1c2..." },
    "timeEntries": [
      {
        "id": "t1...",
        "totalHours": 8,
        "regularHours": 8,
        "overtimeHours": 0,
        "employee": { "id": "e1f2...", "firstName": "John", "lastName": "Smith", "employeeNumber": "EMP-001" }
      }
    ],
    "totals": { "totalHours": 8, "regularHours": 8, "overtimeHours": 0 }
  }
}

Update a pay period

PUT /api/v1/admin/pay-periods/{id}
id
string
required
The pay period’s UUID.
All body fields are optional; only provided fields are applied.
status
string
One of OPEN, SUBMITTED, APPROVED, PAID, CLOSED.
locked
boolean
Lock or unlock the pay period.
payDate
string
ISO-8601 datetime or YYYY-MM-DD.
exportedBy
string
Marks the period as exported; the server also stamps exportedAt with the current time.
iifFilename
string
Filename of the generated QuickBooks IIF export.
Returns 200 with the updated pay period. Returns 404 if not found, 403 for cross-organization access.

Delete a pay period

DELETE /api/v1/admin/pay-periods/{id}
id
string
required
The pay period’s UUID.
Permanently deletes the pay period. Returns 400 Cannot delete pay period if it has any associated time entries. Returns 404 if not found, 403 for cross-organization access.
Response (200)
{
  "success": true,
  "message": "Pay period deleted successfully"
}