uAttend API Follow
The WorkWell Technologies API allows you to programmatically retrieve employee, timecard, and punch data from your uAttend account. All endpoints use HTTPS and are authenticated via an API key.
In this article:
- Authentication
- Base URL
- Available Endpoints
- Endpoint: GET /user
- Endpoint: POST /timecards
- Endpoint: POST /reports/punch
- Common Errors & Troubleshooting
- Appendix: Full User Schema
Authentication
Authentication uses an API key passed in the x-api-key request header. API keys are account-scoped — they grant access to all data within your uAttend account.
- Keys are tied to your uAttend account and are active immediately upon issuance.
- Store your API key securely — treat it like a password. Do not commit it to source control.
Obtaining an API Key
To request an API key, contact our support team or create a ticket.
Please include the following information in your request:
- What system are you looking to integrate with?
- How you plan to use the data retrieved from the API?
- How often you plan to make requests?
Once confirmed, we will arrange for an API key.
Example Authenticated Request
curl -X POST https://api.workwelltech.com/user \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
IP Restrictions & Network Access
The WorkWell Technologies API is accessible over the public internet. However, in some configurations the API Gateway may enforce IP-based access policies at the infrastructure level.
| WARNING: 403 Forbidden — Explicit Deny (Common Issue) | |
| • | Error message: "User is not authorized to access this resource with an explicit deny in an identity-based policy" |
| • | Cause: Your API key is valid, but an AWS resource policy on the API Gateway is blocking the request based on your network origin. |
| • | This is NOT an API key problem — the key is correct and active. |
| • | To find your outbound IP, run: curl https://api.ipify.org from the machine making the API call. |
Base URL
https://api.workwelltech.com
Available Endpoints
| Field | Type | Description | Req. Parameters |
|---|---|---|---|
| POST /user | User | Retrieve user records for the account | None |
| POST /timecards | User | Retrieve timecard data for a user and pay period | UserId |
| POST /reports/punch | User | Retrieve raw punch records across a date range | StartDate, EndDate, UsePaging |
Request Format
Every request must include the following HTTP headers:
| Field | Type | Description |
|---|---|---|
| x-api-key | string | Your API key (provided by WorkWell Technologies support) |
| Content-Type | application/json | Must be set to application/json for all requests |
Request bodies are JSON objects. Even when no parameters are needed, pass an empty JSON object:
-d '{}'
Endpoint: GET /user
Returns user records for your uAttend account. By default, all users are returned. Use the optional request body parameters to filter by user ID, name, or payroll number.
Request
| Field | Type | Description |
|---|---|---|
| Method | POST | |
| URL | https://api.workwelltech.com/user | |
| x-api-key | header | Your API key |
| Content-Type | header | application/json |
Request Body Parameters
All parameters are optional. Omit them or pass {} to return all users.
| Field | Type | Description |
|---|---|---|
| UserId | integer (optional) | Filter to a specific user by their numeric ID |
| Name | string (optional) | Filter by partial or full name match |
| PayrollNumber | string (optional) | Filter by payroll number |
Example — All Users
curl -X POST https://api.workwelltech.com/user \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
Example — Single User
curl -X POST https://api.workwelltech.com/user \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"UserId": 12345}'
Response
The response contains a Users array. Each element represents one user.
Users — Core Fields
These are the fields most commonly used for integration. For the full schema, see the Appendix.
| Field | Type | Description |
|---|---|---|
| UserId | number | Unique numeric identifier for the user |
| FirstName | string | First name |
| LastName | string | Last name |
| Role | string | Role: Admin, Supervisor, or Employee |
| DepartmentId | number | Numeric ID of the user’s home department |
| IsActive | boolean | true if the user is currently active |
| string | Email address | |
| PayrollNumber | string | Payroll number (if configured) |
| PhoneNumber | string | Phone number (if configured) |
| EmployeeReferenceID | string | Custom employee reference ID |
| EmployeeReferenceNote | string | Notes associated with the employee reference |
Endpoint: POST /timecards
Returns the timecard for a specified user. If no date is provided, the current pay period is returned. If a date is supplied, the timecard covering that date is returned.
Request
| Field | Type | Description |
|---|---|---|
| Method | POST | |
| URL | https://api.workwelltech.com/timecards | |
| x-api-key | header | Your API key |
| Content-Type | header | application/json |
Request Body Parameters
| Field | Type | Description |
|---|---|---|
| UserId | integer (required) | The ID of the user whose timecard to retrieve |
| Date | string (optional) | A date within the desired pay period. Format: yyyy-mm-dd. Defaults to the current pay period if omitted. |
Example Requests
# Current pay period
curl -X POST https://api.workwelltech.com/timecards \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"UserId": 12345}'
# Specific pay period (date within it)
curl -X POST https://api.workwelltech.com/timecards \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"UserId": 12345, "Date": "2024-01-15"}'
Data Formatting Notes
| Time & Date Conventions | |
| • | All time durations are strings in HH:mm format. Example: 40 hours = "40:00", 4 hours 15 min = "4:15". |
| • | All dates are strings in yyyy-mm-dd format. Example: "2024-02-15". |
| • | Punch times (InTime, OutTime) are strings in 12-hour format: "08:00 AM". |
| • | Pay codes: REG = Regular, OT1 = Overtime 1, OT2 = Overtime 2, VAC = Vacation, SIC = Sick, HOL = Holiday, OTH = Other. |
Response Schema
The timecard response is a nested object. The hierarchy is:
- GetTimeCardResponse — top-level wrapper
- Timecard — pay period totals and nested lists
- Workdays — list of individual work days
- PunchPairs — list of in/out punch pairs per day
- Tips — list of tip records
- Accruals — list of benefit accrual balances
- ExtendedPunchData — advanced data (PunchHistory, JobPunches, Expenses, Tips by day)
GetTimeCardResponse
| Field | Type | Description |
|---|---|---|
| PayrollNumber | string | Payroll number of the user |
| ApprovalVerbiage | string | Approval status of the timecard |
| IsLock | integer | 1 if the timecard is locked |
| FirstName | string | First name |
| LastName | string | Last name |
| StartDate | string (Date) | Pay period start date (yyyy-mm-dd) |
| EndDate | string (Date) | Pay period end date (yyyy-mm-dd) |
| CurrentPayPeriodStart | string | Start of the current pay period |
| CurrentPayPeriodEnd | string | End of the current pay period |
| Timecard | Timecard | Timecard totals object (see below) |
| ExtendedPunchData | List<TimecardPunchData> | Extended punch data grouped by date |
| Jobs | List<JobSimple> | Job information (JobID, JobNumber, JobName, JobDetails) |
| Departments | List<Department> | Departments accessible to the user |
| ExpenseCodes | List<ExpenseCode> | Expense codes available |
| HomeDepartment | HomeDepartment | Home department details |
Timecard
| Field | Type | Description |
|---|---|---|
| StartDate | string (Date) | Pay period start date |
| EndDate | string (Date) | Pay period end date |
| FirstName | string | First name |
| LastName | string | Last name |
| PayrollNumber | string | Payroll number |
| WeekCount | integer | Number of weeks in the pay period (1–6) |
| Week1 – Week6 | string | Total hours worked per week (HH:mm). Unused weeks return "0:00" |
| RegularTime | string | Total regular hours (HH:mm) |
| Overtime1Time | string | Total overtime 1 hours (HH:mm) |
| Overtime2Time | string | Total overtime 2 hours (HH:mm) |
| VacationTime | string | Total vacation hours (HH:mm) |
| HolidayTime | string | Total holiday hours (HH:mm) |
| SickTime | string | Total sick hours (HH:mm) |
| OtherTime | string | Total other hours (HH:mm) |
| SumOfTotalHours | string | Grand total of all pay code hours (HH:mm) |
| RegularGrossPay | string | Gross pay for regular time |
| Overtime1GrossPay | string | Gross pay for overtime 1 |
| Overtime2GrossPay | string | Gross pay for overtime 2 |
| VacationGrossPay | string | Gross pay for vacation |
| HolidayGrossPay | string | Gross pay for holiday |
| SickGrossPay | string | Gross pay for sick time |
| OtherGrossPay | string | Gross pay for other time |
| TotalGrossPay | string | Total gross pay across all pay codes |
| EmployeeReferenceID | string | Employee reference ID |
| ClientReferenceID | string | Client reference ID |
| Workdays | List<Workday> | List of individual workday records |
| Tips | List<Tip> | List of tip records |
| Accruals | List<Accrual> | List of benefit accrual balances |
Workday
One entry per day that has punch activity. Contains daily totals and a list of PunchPairs.
| Field | Type | Description |
|---|---|---|
| Day1 | string | Day abbreviation (e.g., "Mon") |
| Day2 | string | Short date (e.g., "11/30/19") |
| Day3 | string | ISO date (e.g., "2019-11-30") |
| RegularTime | string | Daily regular hours (HH:mm) |
| Overtime1Time | string | Daily overtime 1 hours (HH:mm) |
| Overtime2Time | string | Daily overtime 2 hours (HH:mm) |
| VacationTime | string | Daily vacation hours (HH:mm) |
| HolidayTime | string | Daily holiday hours (HH:mm) |
| SickTime | string | Daily sick hours (HH:mm) |
| OtherTime | string | Daily other hours (HH:mm) |
| PunchPairs | List<PunchPair> | List of individual in/out punch pairs for this day |
PunchPair
One entry per in/out punch pair. The last punch pair of a day has IsLast = 1.
| Field | Type | Description |
|---|---|---|
| PunchId | string | Unique punch identifier |
| Paycode | string | Pay code (1=Regular, 6=Break, 7=Lunch) |
| DepartmentName | string | Department name for regular punches; "Break" or "Lunch" for paycodes 6/7 |
| InDate | string | In punch date (yyyy-mm-dd) |
| OutDate | string | Out punch date (yyyy-mm-dd) |
| InTime | string | In punch time (hh:mm AM/PM) |
| OutTime | string | Out punch time (hh:mm AM/PM) |
| RegularHours | string | Regular hours for this punch pair (HH:mm) |
| Overtime1Hours | string | Overtime 1 hours for this punch pair (HH:mm) |
| Overtime2Hours | string | Overtime 2 hours for this punch pair (HH:mm) |
| VacationHours | string | Vacation hours for this punch pair (HH:mm) |
| HolidayHours | string | Holiday hours for this punch pair (HH:mm) |
| SickHours | string | Sick hours for this punch pair (HH:mm) |
| OtherHours | string | Other hours for this punch pair (HH:mm) |
| TotalHours | string | Total hours for this punch pair (HH:mm) |
| RegularGrossPay | number | Gross pay — regular time |
| TotalGrossPay | number | Total gross pay for this punch pair |
| Description | string | Optional description |
| Note | string | Optional note |
| IsLast | integer | 1 if this is the last punch pair for the day |
Tip
| Field | Type | Description |
|---|---|---|
| TipId | integer | Unique tip identifier |
| TipCode | string | Tip code |
| TotalMinutes | string | Total minutes for the tip entry |
| TipDepartmentName | string | Department associated with the tip |
| TotalTipMinute | string | Total tip minutes |
Accrual
| Field | Type | Description |
|---|---|---|
| Code | string | Benefit category code (e.g., "VAC", "SIC") |
| Accrued | string | Total accrued balance (HH:mm, e.g., "80:00") |
| Used | string | Hours used (HH:mm, e.g., "20:00") |
| Available | string | Remaining available balance (HH:mm, e.g., "60:00") |
TimecardPunchData (ExtendedPunchData)
Extended data grouped by date, available in the ExtendedPunchData list.
| Field | Type | Description |
|---|---|---|
| Date | string | Date the records belong to (yyyy-mm-dd) |
| PunchHistory | List<PunchHistory> | Punch edit history for the day |
| Tips | List<TimecardRowMonetaryDeduction> | Tip entries for the day |
| JobPunches | List<JobPunches> | Job-specific punch records for the day |
| Expenses | List<TimecardRowMonetaryDeduction> | Expense entries for the day |
JobPunches
| Field | Type | Description |
|---|---|---|
| UserId | integer | User identifier |
| PunchId | integer | Punch identifier |
| JobId | integer | Job identifier |
| JobNumber | string | Job number |
| JobName | string | Job name |
| JobDetailId | integer | Job detail identifier |
| JobDetailName | string | Job detail name |
| JobInDate | string | Job in punch date |
| JobInTime | string | Job in punch time |
| JobOutDate | string | Job out punch date |
| JobOutTime | string | Job out punch time |
| DepartmentId | integer | Department identifier |
| JobDescription | string | Job description |
| JobNote | string | Job note |
| SubJobDetails | List<JobPunches> | Nested sub-job punch records |
Endpoint: POST /reports/punch
Returns raw punch records for one or more users over a specified date range. Supports pagination for large result sets. If no user IDs are supplied, punches for all account users are returned.
Request
| Field | Type | Description |
|---|---|---|
| Method | POST | |
| URL | https://api.workwelltech.com/reports/punch | |
| x-api-key | header | Your API key |
| Content-Type | header | application/json |
Request Body Parameters
| Field | Type | Description |
|---|---|---|
| StartDate | string (required) | Start of the date range (yyyy-mm-dd) |
| EndDate | string (required) | End of the date range (yyyy-mm-dd). Maximum range: 3 months from StartDate. |
| UserIds | List<integer> (opt) | Filter to specific user IDs. Returns all users if omitted or empty. |
| UsePaging | boolean (required) | Set to true to paginate results. Set to false to return all results at once. |
| PageSize | integer (opt) | Number of records per page. Required when UsePaging is true. |
| PageNumber | integer (opt) | 0-indexed page number to retrieve. Required when UsePaging is true. |
| Date Range Limit | |
| • | EndDate cannot be more than 3 months after StartDate. |
| • | For larger ranges, make multiple requests with sequential date windows. |
Example — All Users, No Paging
curl -X POST https://api.workwelltech.com/reports/punch \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"StartDate": "2024-01-01",
"EndDate": "2024-01-31",
"UsePaging": false
}'
Example — Specific Users, With Paging
curl -X POST https://api.workwelltech.com/reports/punch \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"StartDate": "2024-01-01",
"EndDate": "2024-03-31",
"UserIds": [12345, 67890],
"UsePaging": true,
"PageSize": 100,
"PageNumber": 0
}'
Response Schema
PunchReportResponse
| Field | Type | Description |
|---|---|---|
| Response | ResponseObject | Success flag and error detail (see below) |
| UsePaging | boolean | Whether results were paginated |
| PageSize | integer | Records per page |
| PageNumber | integer | Current page (0-indexed) |
| Total | integer | Total matching records (when paging is off) |
| UserIds | List<long> | User IDs included in results. Empty = all users |
| PunchReportLineItems | List<PunchReportLineItem> | The punch records (see below) |
ResponseObject
| Field | Type | Description |
|---|---|---|
| Success | boolean | true if the request completed without errors |
| Keys | Dictionary<string, List<string>> | Error message keys paired to the field they relate to |
| Messages | Dictionary<string, List<string>> | Human-readable error messages paired to the field |
PunchReportLineItem
One record per in/out punch pair.
| Field | Type | Description |
|---|---|---|
| Id | long | Unique punch record identifier |
| UserId | integer | User the punch belongs to |
| DepartmentId | integer | Department the punch is attributed to |
| PaycodeId | integer | 1=Regular, 2=Vacation, 3=Sick, 4=Holiday, 5=Other |
| PunchDay | integer | Unix integer representing the workday date |
| PunchDate | Date | Workday date (Date object) |
| DayAbbrev | string | Day of week abbreviation: Mon, Tue, Wed, Thu, Fri, Sat, Sun |
| DepartmentCode | string | Department code |
| DepartmentName | string | Department name |
| FirstName | string | User’s first name |
| LastName | string | User’s last name |
| PayrollNumber | string | Payroll number if present |
| InDate | Date | Date of the in punch |
| InTime | Time | Time of the in punch |
| OutDate | Date | Date of the out punch |
| OutTime | Time | Time of the out punch |
| Tot | string | Total punch pair duration in HH:mm format (e.g., "4:15") |
| InPunchLocation | string | Where the in punch was made: IP address (web), timeclock ID, or geolocation (smartphone) |
| OutPunchLocation | string | Where the out punch was made: IP address (web), timeclock ID, or geolocation (smartphone) |
| InPunchMethod | string | Method of in punch: Time Clock, Manual Edit, Smartphone App, Website |
| OutPunchMethod | string | Method of out punch: Time Clock, Manual Edit, Smartphone App, Website |
Common Errors & Troubleshooting
| Code | Name | Cause & Resolution |
|---|---|---|
| 400 | Bad Request | Malformed JSON in the request body, or a required field is missing. Check your request body for syntax errors and verify required fields are present. |
| 401 | Unauthorized | The x-api-key header is missing or the key value is incorrect. Verify the header name is exactly x-api-key (lowercase) and that the key value is complete and unmodified. |
| 403 | Forbidden — Explicit Deny | Your API key is valid but an AWS identity-based policy is blocking the request. This is a network/IP restriction, not a key issue. Provide your outbound IP to WorkWell Technologies support for resolution. |
| 403 | Forbidden — Other | The API key is valid but does not have permission to access the requested resource. Contact support to verify key permissions. |
| 403 | Forbidden — Missing Authentication Token | The endpoint URL is incorrect. Verify the URL path, stage (e.g., /user, /timecards, or /reports/punch), and HTTP method. This error is often caused by a typo in the endpoint URL. |
| 404 | Not Found | The endpoint URL is incorrect. Verify the path matches exactly: /user, /timecards, or /reports/punch. |
| 429 | Too Many Requests | Rate limit exceeded. Slow down the request frequency and implement retry logic with exponential backoff. |
| 500 | Internal Server Error | An unexpected server-side error occurred. If this persists, contact WorkWell Technologies support with your request details and timestamp. |
Diagnosing a 403 Explicit Deny
The error message "User is not authorized to access this resource with an explicit deny in an identity-based policy" is generated by AWS API Gateway when a resource policy is in place that explicitly blocks the request.
Follow these steps:
- Confirm your x-api-key header and value are correct.
- Run the following to find your machine’s public outbound IP:
curl https://api.ipify.org
- Contact WorkWell Technologies support with your API key (last 4 characters only) and your outbound IP address.
- Support will verify that the API Gateway resource policy permits requests from your IP range.
| Internal Network Note | |
| • | If testing from within a corporate network or VPN, your outbound IP may differ from what you expect. |
| • | Try running the curl call from the actual server or environment that will make production API calls. |
| • | Ensure your request is going to the public internet address, not an internal proxy. |
General Troubleshooting Checklist
- Header name is exactly: x-api-key (all lowercase, hyphen not underscore)
- Header value contains the full API key with no trailing spaces or line breaks
- Content-Type is set to: application/json
- Request body is valid JSON (even {} for parameterless calls)
- URL uses HTTPS, not HTTP
- Date strings use yyyy-mm-dd format
- EndDate is within 3 months of StartDate (for punch reports)
Appendix: Full User Schema
The following table documents all available fields in the user object. The /user endpoint returns the core fields by default. The full internal schema is provided here for reference.
| Field | Type | Description |
|---|---|---|
| id | number | Internal user identifier |
| account_id | integer | Account identifier |
| role_id | integer | Role: 1=Admin, 2=Supervisor, 3=Employee |
| right_id | integer | Timecard edit rights: 1=true, 0=false |
| department_id | integer | Home department identifier |
| timezone_id | integer | Timezone identifier |
| string | Email address | |
| first_name | string | First name |
| last_name | string | Last name |
| phone | string | Phone number |
| payroll_number | string | Payroll number |
| pin_number | string | PIN number |
| badge_number | string | Badge number |
| weekly_rule | boolean | Weekly overtime rule enabled |
| last_punch | string (Date) | Date of the user’s last regular punch |
| last_punch_type | integer | Last punch method: 1=Web, 2=Phone, 3=Terminal, 4=Manual |
| last_punch_location | string | Location string for last punch (timeclock name, IP, geolocation) |
| vacation_start_date | string (Date) | Vacation accrual start date |
| vacation_start_balance | number | Vacation starting balance |
| vacation_rate | number | Vacation accrual rate |
| sick_start_date | string (Date) | Sick accrual start date |
| sick_start_balance | number | Sick starting balance |
| sick_rate | number | Sick accrual rate |
| other_start_date | string (Date) | Other accrual start date |
| other_start_balance | number | Other accrual starting balance |
| other_rate | number | Other accrual rate |
| created_date | string (Date) | Account creation date |
| inactive_date | string (Date) | Date user was deactivated (if applicable) |
| is_timecard_viewable | boolean | Whether the user can view their timecard |
| is_accrual_viewable | boolean | Whether the user can view accrual balances |
| is_department_transfer | boolean | Whether department transfer is enabled |
| is_ip_limited | boolean | Whether smartphone punching is IP-restricted |
| is_callerid_limited | boolean | Whether call punching is caller-ID restricted |
| is_holiday | boolean | Whether holiday tracking is enabled |
| is_active | boolean | Whether the user is currently active |
| enable_notify | boolean | Email notification enabled |
| allow_iphone_punch | boolean | uAttend app punching allowed |
| employee_approval | boolean | Employee timecard approval required |
| allow_website_punch | boolean | Website punch allowed |
| smartphone_access | boolean | Smartphone portal access enabled |
| allow_group_punch | boolean | Group punch allowed |
| visit_count | integer | Total portal visits |
| notice | string | Notice text |
| notes | string | Internal notes |
| last_punch_id | number | Identifier of the last punch record |