Skip to main content
The PayPunch API is a versioned JSON REST API for building integrations against your PayPunch data — bookkeeper organizations, pay periods, and employee timesheets. This reference is generated from the real /api/v1 route handlers.
This API is for programmatic access. The PayPunch web app and mobile clients use these same endpoints. Treat tokens and credentials as secrets.

Base URL

Every endpoint is mounted under /api/v1 on your PayPunch deployment.
https://app.paypunch.io/api/v1
The host is whatever your deployment’s NEXT_PUBLIC_APP_URL resolves to. All paths in this reference are written relative to the /api/v1 prefix (for example, POST /auth/login is POST {baseURL}/api/v1/auth/login).

Versioning

The version is encoded in the URL path (/api/v1/...). A breaking change ships under a new prefix (/api/v2), so integrations pinned to v1 keep working.

Response envelope

Every endpoint returns the same JSON envelope:
{
  "success": true,
  "data": { },
  "error": "string (only on failure)",
  "message": "string (optional human-readable detail)"
}
success
boolean
required
true when the request succeeded, false otherwise. Always present.
data
object
The result payload. Present on success. Its shape is documented per endpoint.
error
string
A short error label (for example, "Authentication required"). Present on failure.
message
string
An optional, more detailed human-readable message. May appear on both success and failure responses.

Authentication responses

Login and verification endpoints embed the JWT inside data alongside the returned record:
{
  "success": true,
  "data": {
    "user": { },
    "token": "eyJhbGciOiJ..."
  }
}

Paginated list responses

List endpoints (such as bookkeeper orgs and pay periods) wrap results in a pagination object inside data:
{
  "success": true,
  "data": {
    "items": [],
    "total": 42,
    "page": 1,
    "pageSize": 20,
    "totalPages": 3
  }
}

Error codes

Errors use standard HTTP status codes with the envelope above (success: false).
Statuserror exampleWhen it happens
400Invalid login data / Overlapping pay periodValidation failed (Zod), or a business rule was violated. message lists the offending fields.
401Authentication failed / Authentication requiredMissing/invalid credentials, or a missing/expired token.
403Access denied / Account inactiveAuthenticated but not allowed (wrong tenant, deactivated account/org/company).
404Pay period not foundThe requested resource does not exist.
429Too many login attemptsRate limit exceeded (login only — see below).
500Login failed / Failed to fetch ...Unexpected server error.
Validation errors come from Zod and return a message of the form field: reason, field: reason.

Rate limits

The login endpoint is rate limited by client IP: 5 attempts per 15 minutes. When exceeded it returns 429 with these headers:
HeaderMeaning
X-RateLimit-LimitMaximum attempts allowed in the window.
X-RateLimit-RemainingAttempts remaining in the current window.
X-RateLimit-ResetISO-8601 timestamp when the window resets.
Rate limiting uses Upstash Redis when UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN are configured, otherwise an in-memory limiter (per-instance). The login limit is the only limit enforced inside the documented /api/v1 handlers; broader per-IP API/public limits exist in the codebase but are not applied by these specific routes.

Next steps

Authentication

How to obtain and send a JWT for admin and employee requests.

Admin: Bookkeeper Orgs

List, create, read, update, and deactivate bookkeeper organizations.