DEVELOPER DOCUMENTATION

Public API

Programmatic, read-only access to your Papervee workspace. Authenticate with a token and pull data across the Papervee platforms - employee leaves and events, plus project management data such as clients, projects and tracked time.

All requests are made over HTTPS to https://api.papervee.com. Replace {tenant_id} in each path with your workspace identifier - you can find it under the Need help button in the bottom-left corner of the screen.

Authentication

Every request must include your workspace token in the x-api-token header. Requests with a missing or invalid token return 401 Unauthorized.

Request header
GET /{tenant_id}/api/public/v1/leaves-events
x-api-token: YOUR_PUBLIC_API_TOKEN

API token

Generate your PUBLIC_API_TOKEN from your workspace App Center — Public API settings (only the workspace owner can generate it). Keep it secret and send it on every request.

Rate limits

Requests are limited per IP. Staying under the limit keeps your integration responsive; exceeding it returns a rate-limit error.

Rate limit

Requests are limited to 60 requests / minute per IP. Exceeding the limit returns 429 Too Many Requests.

Papervee Core

Workspace-level data: employee leaves and events.

GET

Leaves & Events feed

/{tenant_id}/api/public/v1/leaves-events

Returns a chronological list of employee leaves (vacation, sick leave, remote work, etc.) and events (business travel, leave of absence, etc.) overlapping a given date range.

Query parameters

start_datestring · YYYY-MM-DDRequired

Start of the period.

end_datestring · YYYY-MM-DDRequired

End of the period. Must be on or after start_date. Maximum range is 366 days.

include_leavesboolean default true

Include leaves in the response.

include_eventsboolean default true

Include events in the response. At least one of include_leaves / include_events must be true.

daily_splitboolean default false

false returns one entry per record (the full period). true returns one entry per day.

Filtering behavior

  • A record is returned if any part of it overlaps the requested range.
  • Records with status Deleted are excluded. Waiting (pending) records are included.
  • Type names are localized to your workspace language.

Response attributes

JSON array, sorted ascending by start date (by day when daily_split=true).

Common fields

Present on every item.

categorystring

"leave" or "event".

idinteger

Unique identifier of the record.

request_typestring

Type code, e.g. VC, WFH, SL, DEL.

request_type_namestring

Localized, human-readable type name (e.g. "Vacation").

statusstring

Record status, e.g. "Approved", "Waiting".

userobject

The employee the record belongs to. See the user object below.

created_atstring · ISO 8601

When the record was created. ISO 8601, UTC (e.g. 2026-05-20T09:12:00.000000Z).

The user object

Nested inside every item.

idinteger

User identifier.

full_namestring

Employee full name.

working_normstring

Contracted working hours per day (e.g. "8").

Event-only fields

Present only when the event type is time-based (event_request_is_on_time = true).

event_request_is_on_timeboolean

Always true when present; marks a time-based event.

duration_msinteger

Duration in milliseconds.

start_timestring · HH:MM

Start time.

end_timestring · HH:MM

End time.

When daily_split=false (default)

Returned in addition to the common fields.

request_periodobject

{ start_date, end_date } in YYYY-MM-DD; reflects the record's full period.

leave_daysinteger

Number of leave days (leaves only).

event_daysinteger

Number of event days (events only).

When daily_split=true

request_period, leave_days and event_days are omitted.

daystring · YYYY-MM-DD

The single day this entry represents.

Errors

400{ "message": "Invalid parameters", "errors": { ... } }

Validation failed; errors names the offending fields.

401{ "message": "Unauthorized" }

Missing or invalid token.

429-

Rate limit exceeded (60 requests / minute per IP).

HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/leaves-events?start_date=2026-06-01&end_date=2026-06-30&daily_split=false
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "category": "leave",
    "id": 12,
    "request_type": "VC",
    "request_type_name": "Vacation",
    "status": "Approved",
    "request_period": { "start_date": "2026-06-01", "end_date": "2026-06-03" },
    "leave_days": 3,
    "user": { "id": 5, "full_name": "Ion Pop", "working_norm": "8" },
    "created_at": "2026-05-20T09:12:00.000000Z"
  },
  {
    "category": "event",
    "id": 3,
    "request_type": "DEL",
    "request_type_name": "Business Travel",
    "status": "Approved",
    "event_request_is_on_time": true,
    "duration_ms": 7200000,
    "start_time": "09:00",
    "end_time": "11:00",
    "request_period": { "start_date": "2026-06-02", "end_date": "2026-06-02" },
    "event_days": 1,
    "user": { "id": 7, "full_name": "Ana Ban", "working_norm": "8" },
    "created_at": "2026-05-22T11:00:00.000000Z"
  }
]

Papervee Projects

Project management data: clients, projects, subprojects, tracked time and employees.

GET

List clients

/{tenant_id}/api/public/v1/projects/clients

Returns all project clients with their project and subproject counts. No query parameters.

Response attributes

200 OK - JSON array. Each item:

Response item

client_idinteger

Client identifier.

client_namestring
brand_namestring
vat_numberstring
trade_register_numberstring
client_codestring
address, city, county, countrystring

Address fields.

iban, bankstring

Banking details.

email, contact_person, phonestring

Contact details.

tax_payeras stored

Tax-payer flag/value.

projects_countinteger

Number of (non-deleted) projects.

subprojects_countinteger

Number of subprojects.

projectsinteger[]

Project IDs.

sub_projectsinteger[]

Subproject IDs.

archivedboolean

True if the client is deleted/archived.

created_atstring · ISO 8601
HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/projects/clients
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "client_id": 1,
    "client_name": "Nord Logistics SRL",
    "brand_name": "Nord Logistics",
    "vat_number": "RO12345678",
    "trade_register_number": "J40/1234/2019",
    "client_code": "CLI-001",
    "address": "Str. Aurel Vlaicu 12",
    "city": "Cluj-Napoca",
    "county": "Cluj",
    "country": "Romania",
    "iban": "RO49BTRL1234567890123456",
    "bank": "Banca Transilvania",
    "email": "office@nordlogistics.ro",
    "contact_person": "Ion Pop",
    "phone": "+40 721 000 000",
    "tax_payer": true,
    "projects_count": 3,
    "subprojects_count": 7,
    "projects": [42, 43, 51],
    "sub_projects": [101, 102, 103],
    "archived": false,
    "created_at": "2025-01-15T08:30:00.000000Z"
  }
]
GET

List projects

/{tenant_id}/api/public/v1/projects

Returns all projects with billing info and assigned users. No query parameters.

Response attributes

200 OK - JSON array. Each item:

Response item

project_idinteger
project_namestring
project_client_idinteger

Owning client ID.

is_billableboolean

Whether the project is billable.

rate_typestring | null

"hourly", "monthly", or null (only set when billable).

project_currencystring | null

Currency code (only when billable).

assigned_usersobject[]

See the user-info object below.

sub_projectsinteger[]

Subproject IDs.

archivedboolean

True if the project is deleted/archived.

created_atstring · ISO 8601
client_vat_codestring

Client's VAT number.

client_contact_personstring
client_county, client_citystring

The user-info object

Each entry in assigned_users.

userIdinteger
first_namestring
last_namestring
full_namestring
emailstring
job_titlestring
avatar_urlstring
HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/projects
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "project_id": 42,
    "project_name": "Website Redesign",
    "project_client_id": 1,
    "is_billable": true,
    "rate_type": "hourly",
    "project_currency": "EUR",
    "assigned_users": [
      {
        "userId": 5,
        "first_name": "Ion",
        "last_name": "Pop",
        "full_name": "Ion Pop",
        "email": "ion.pop@company.com",
        "job_title": "Frontend Developer",
        "avatar_url": "https://cdn.papervee.com/avatars/5.png"
      }
    ],
    "sub_projects": [101, 102],
    "archived": false,
    "created_at": "2025-02-01T09:00:00.000000Z",
    "client_vat_code": "RO12345678",
    "client_contact_person": "Ion Pop",
    "client_county": "Cluj",
    "client_city": "Cluj-Napoca"
  }
]
GET

List subprojects of a project

/{tenant_id}/api/public/v1/projects/{project_id}/subprojects

Returns the subprojects belonging to a project.

Path parameters

project_idintegerRequired

Project identifier.

Response attributes

200 OK - JSON array. Each item:

Response item

client_idinteger

The parent project's client ID.

subproject_idinteger
subproject_namestring
completedboolean

True when status is complete.

time_estimatednumber

Estimated time in seconds.

time_spentnumber

Total tracked time in seconds.

HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/projects/42/subprojects
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "client_id": 1,
    "subproject_id": 101,
    "subproject_name": "Landing pages",
    "completed": false,
    "time_estimated": 144000,
    "time_spent": 90000
  }
]
GET

Users' tracked time entries

/{tenant_id}/api/public/v1/projects/users

Returns locked project-tracking time entries per user within a date range.

Query parameters

start_datestring · YYYY-MM-DDTHH:MM:SSRequired

ISO datetime, e.g. 2026-06-01T00:00:00.

end_datestring · YYYY-MM-DDTHH:MM:SSRequired

Must be on or after start_date. The range may not exceed 31 days.

Filtering behavior

  • Only time entries with status locked whose start and end fall inside the range are included.

Response attributes

200 OK - JSON array. Each item:

Response item

user_idinteger
userobject

{ first_name, last_name, email }.

time_entriesobject[]

See the time-entry object below.

The time-entry object

Each entry in time_entries.

client_idinteger
project_idinteger
subproject_idinteger
start_timestring · ISO 8601
end_timestring · ISO 8601
descriptionstring
time_spentnumber

Duration in seconds.

Errors

400{ "message": "Invalid dates" }

Missing/malformed dates or end_date before start_date.

400{ "message": "Requested period greater than a month" }

Range exceeds 31 days.

HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/projects/users?start_date=2026-06-01T00:00:00&end_date=2026-06-30T23:59:59
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "user_id": 5,
    "user": { "first_name": "Ion", "last_name": "Pop", "email": "ion.pop@company.com" },
    "time_entries": [
      {
        "client_id": 1,
        "project_id": 42,
        "subproject_id": 101,
        "start_time": "2026-06-01T09:00:00.000000Z",
        "end_time": "2026-06-01T12:30:00.000000Z",
        "description": "Implemented hero section",
        "time_spent": 12600
      }
    ]
  }
]
GET

List employees

/{tenant_id}/api/public/v1/projects/employees

Returns active employees with job title, public custom fields, and team memberships. No query parameters.

Response attributes

200 OK - JSON array. Each item:

Response item

idinteger

User ID.

first_namestring
last_namestring
emailstring
job_titlestring

From contract data.

custom_categoriesobject[]

Public custom fields grouped by category. See the custom-category object below.

teamsobject[]

Project memberships. See the team object below.

The custom-category object

Each entry in custom_categories. Only custom fields marked public are included.

categorystring
fieldsobject[]

Array of { custom_field_id, custom_field_name, custom_field_value }.

The team object

Each entry in teams.

project_idinteger
namestring
has_manage_rightsboolean
HTTP
GET https://api.papervee.com/{tenant_id}/api/public/v1/projects/employees
x-api-token: YOUR_PUBLIC_API_TOKEN
JSON
[
  {
    "id": 5,
    "first_name": "Ion",
    "last_name": "Pop",
    "email": "ion.pop@company.com",
    "job_title": "Frontend Developer",
    "custom_categories": [
      {
        "category": "Personal",
        "fields": [
          { "custom_field_id": 3, "custom_field_name": "T-shirt size", "custom_field_value": "L" }
        ]
      }
    ],
    "teams": [
      { "project_id": 42, "name": "Website Redesign", "has_manage_rights": true }
    ]
  }
]

Papervee Time Tracking

Write endpoints for an employee's work timer - clock in/out and pause/resume. Each request takes a JSON body and identifies the employee with user_id or email (at least one; user_id wins if both are sent). Datetimes are sent in UTC / ISO-8601 and converted to the employee's timezone before storing.

POST

Clock in

/{tenant_id}/api/public/v1/start-time

Starts a running work timer for an employee. Fails if the employee already has an active timer.

Body parameters

user_idintegerRequired

Employee id. Provide this or email.

emailstringRequired

Employee email. Provide this or user_id.

start_timestring · YYYY-MM-DDTHH:MM:SSZ

When work starts, in UTC, e.g. 2026-06-29T08:00:00Z. Optional. If omitted, the current time in the user's timezone is used.

project_idinteger

Project to attach. Saved only when project time-tracking is enabled for the employee and they can manage the project.

subproject_idinteger

Subproject to attach. Saved only alongside a valid project_id it belongs to.

Errors

400{ "error": "Active time already exists" }

The employee already has a running or paused timer.

400{ "message": "Invalid parameters", "errors": { ... } }

Missing or invalid user_id / email / start_time.

HTTP
POST https://api.papervee.com/{tenant_id}/api/public/v1/start-time
x-api-token: YOUR_PUBLIC_API_TOKEN
Content-Type: application/json

{
  "user_id": 5,
  "start_time": "2026-06-29T08:00:00Z",
  "project_id": 42,
  "subproject_id": 101
}
200 OK
{ "message": "Time started successfully" }
POST

Clock out

/{tenant_id}/api/public/v1/stop-time

Stops the employee's running work timer and records the finalized work entry. A session shorter than one minute is discarded - the timer is removed and no entry is written.

Body parameters

user_idintegerRequired

Employee id. Provide this or email.

emailstringRequired

Employee email. Provide this or user_id.

end_timestring · YYYY-MM-DDTHH:MM:SSZ

When work stops, in UTC. Must be after the timer's start. Optional. If omitted, the current time in the user's timezone is used.

Errors

400{ "error": "No active time to stop" }

The employee has no active timer.

400{ "error": "End time must be after start time" }

end_time is at or before the timer's start.

400{ "message": "Invalid parameters", "errors": { ... } }

Missing or invalid user_id / email / end_time.

HTTP
POST https://api.papervee.com/{tenant_id}/api/public/v1/stop-time
x-api-token: YOUR_PUBLIC_API_TOKEN
Content-Type: application/json

{
  "user_id": 5,
  "end_time": "2026-06-29T16:30:00Z"
}
200 OK
{ "message": "Time stopped successfully" }
POST

Start pause

/{tenant_id}/api/public/v1/start-pause

Puts a running work timer on pause: closes the open work segment and opens a pause timer in its place. Requires a currently running (work) timer. A work segment shorter than one minute is discarded, but the transition to pause still happens.

Body parameters

user_idintegerRequired

Employee id. Provide this or email.

emailstringRequired

Employee email. Provide this or user_id.

start_timestring · YYYY-MM-DDTHH:MM:SSZ

When the pause begins, in UTC. Must be after the work segment started. Optional. If omitted, the current time in the user's timezone is used.

Errors

400{ "error": "No active time to pause" }

The employee has no active timer.

400{ "error": "Active time is not running" }

The employee is already on pause, not working.

400{ "error": "Pause start must be after the work start time" }

start_time is at or before the work segment's start.

400{ "message": "Invalid parameters", "errors": { ... } }

Missing or invalid user_id / email / start_time.

HTTP
POST https://api.papervee.com/{tenant_id}/api/public/v1/start-pause
x-api-token: YOUR_PUBLIC_API_TOKEN
Content-Type: application/json

{
  "user_id": 5,
  "start_time": "2026-06-29T12:00:00Z"
}
200 OK
{ "message": "Pause started successfully" }
POST

Stop pause (resume)

/{tenant_id}/api/public/v1/stop-pause

Resumes from pause: closes the open pause segment and opens a new work timer in its place. Requires a currently paused timer. A pause segment shorter than one minute is discarded, but work still resumes.

Body parameters

user_idintegerRequired

Employee id. Provide this or email.

emailstringRequired

Employee email. Provide this or user_id.

end_timestring · YYYY-MM-DDTHH:MM:SSZ

When work resumes, in UTC. Must be after the pause started. Optional. If omitted, the current time in the user's timezone is used.

project_idinteger

Project to attach to the resumed work timer. Saved only when project time-tracking is enabled for the employee and they can manage the project.

subproject_idinteger

Subproject to attach. Saved only alongside a valid project_id it belongs to.

Errors

400{ "error": "No active pause to stop" }

The employee has no active timer.

400{ "error": "Active time is not paused" }

The employee is working, not on pause.

400{ "error": "End time must be after start time" }

end_time is at or before the pause's start.

400{ "message": "Invalid parameters", "errors": { ... } }

Missing or invalid user_id / email / end_time.

HTTP
POST https://api.papervee.com/{tenant_id}/api/public/v1/stop-pause
x-api-token: YOUR_PUBLIC_API_TOKEN
Content-Type: application/json

{
  "user_id": 5,
  "end_time": "2026-06-29T13:00:00Z",
  "project_id": 42,
  "subproject_id": 101
}
200 OK
{ "message": "Pause stopped successfully" }

Papervee Users

User management: create an employee with their profile, contract, leave balance, settings and module access in a single call.

POST

Create user

/{tenant_id}/api/public/v1/users

Creates a new employee in the workspace — the same result as adding one from the Papervee interface: the profile, contract, leave balance, settings and module access are all set up in one call. Choose between two flows with invited_by_email: email invitation — the employee receives an invitation email with a link (valid for 2 days) where they set their own password — or manual add — the account is usable immediately, and the employee is asked to change the supplied password on first login.

Body parameters

first_namestringRequired

Employee first name. Max 255 characters.

last_namestringRequired

Employee last name. Max 255 characters.

emailstringRequired

With invited_by_email: true, a valid, unused email address — the invitation is sent to it. With invited_by_email: false it is a workspace username, not a real address: the tenant domain is added as a prefix (e.g. mihai.tatu in the induserv workspace is stored as induserv.mihai.tatu), and the combined value must be at most 50 characters and unused.

invited_by_emailbooleanRequired

true = send an invitation email (the employee is created as pending and activates the account through the emailed link); false = manual add, the account is active immediately.

passwordstring

Required when invited_by_email is false and can_log_in is not false. Minimum 6 characters, containing at least two of: lowercase letters, uppercase letters, digits. Not accepted on the email-invitation flow (the employee sets their own password there).

password_confirmationstring

Required whenever password is sent. Must match password exactly.

can_log_inboolean default true

Manual flow only. Set to false to create an employee who cannot log in (no password needed then). null is not accepted — send true, false, or omit the field.

send_invitation_to_userboolean default true

Email flow only. Set to false to create the pending employee without sending the invitation email yet.

job_titlestringRequired

Max 255 characters.

hire_datestring · YYYY-MM-DDRequired

Contract start date, e.g. 2026-08-25. Must be between 1900-01-01 and 2100-12-31.

working_normeintegerRequired

Daily working norm in hours, 1–24.

has_meal_vouchersboolean default false

Whether the contract includes meal vouchers.

leave_daysintegerRequired

Annual leave days on the contract, 0–365.

available_leave_daysintegerRequired

Leave days currently available to the employee, 0–365.

vacation_days_carried_over_previous_yearintegerRequired

0–365. Leave days the employee carried over from the previous year — include these in available_leave_days if not yet used.

core_module_accessboolean default false

Grants access to the Core HR module. Requires an active core subscription; the seat is added to it. At least one of core_module_access / performance_module_access must be true.

performance_module_accessboolean default false

Grants access to the Performance module. Requires an active performance subscription; the seat is added to it.

performance_module_admin_roleboolean default false

With performance access: true = Performance admin, false = Performance user.

project_tracking_module_accessboolean default false

Grants access to project time-tracking. Requires an active core subscription.

project_tracking_module_admin_roleboolean default false

With project-tracking access: true = admin role, false = user role.

recruitment_module_accessboolean default false

Grants access to the Recruitment module.

Good to know

  • The workspace owner is recorded as the inviter of the invitation email and becomes the new employee's manager.
  • The invitation link expires after 2 days; it can be re-sent later from the Papervee interface.

Errors

400{ "message": "Invalid parameters", "errors": { "field": ["reason"] } }

Validation failed; errors names the offending fields and the reasons.

400{ "error": "..." }

Business-rule violation. The error message is one of: User must have access at minimum one base subscription, Core module access requires an active core subscription, Performance module access requires an active performance subscription, or Project tracking module access requires an active core subscription.

401{ "message": "Unauthorized" }

Missing or invalid x-api-token.

403{ "error": "Payment needed!" }

No active subscription on the workspace.

HTTP
POST https://api.papervee.com/{tenant_id}/api/public/v1/users
x-api-token: YOUR_PUBLIC_API_TOKEN
Content-Type: application/json

{
  "first_name": "Andreea",
  "last_name": "Pop",
  "email": "andreea.pop@example.com",
  "invited_by_email": true,
  "job_title": "QA Engineer",
  "hire_date": "2026-09-01",
  "working_norme": 8,
  "has_meal_vouchers": true,
  "leave_days": 21,
  "available_leave_days": 21,
  "vacation_days_carried_over_previous_year": 0,
  "core_module_access": true
}
200 OK
{ "message": "User created successfully", "user_id": 123 }
Ready to start?

Simplify and digitize HR flows in your company and help the team focus on projects that truly matter.