Identify the company
Provide the AppyShift company name and portal slug, plus an authorized business contact and a technical contact.
AppyShift API · v1 · Public beta
Sync employees, schedules, time, credentials, organization data, and reports, then receive signed workforce events through one tenant-scoped API.
API access requires prior approval. Contact AppyShift Support to authorize your company and integration before requesting a token.
https://www.appyshift.com/{company_slug}
The AppyShift API is designed for server-to-server integrations. Every credential, token, workforce resource, report, and result is restricted to the company slug in the request URL.
The API is not self-service during public beta. An authorized company representative or integration partner must contact AppyShift Support and receive approval before credentials are provisioned.
{company_slug} with the client’s AppyShift portal slug.The documentation is public, but API credentials are issued only for approved company integrations. Send AppyShift Support enough context to review the request, confirm the company, and grant the smallest appropriate set of permissions.
Provide the AppyShift company name and portal slug, plus an authorized business contact and a technical contact.
Explain the system being connected, the business purpose, expected request volume, and whether webhooks or write access are needed.
List the resources and scopes required. Requests involving sensitive report fields receive an additional authorization review.
After approval, an AppyShift Super Admin provisions a named OAuth client and coordinates the one-time credential handoff.
AppyShift uses the OAuth 2.0 client-credentials grant for machine-to-machine API access. After Support approves the integration, an AppyShift Super Admin creates each named client for the company. Store the one-time secret in the calling system’s secret manager.
Client secrets are password-hashed and access tokens are SHA-256 hashed. Rotating a secret or revoking a client immediately invalidates its issued tokens.
See the token request and response exampleNeed credentials first? Request authorization from Support.
Once your intended integration is approved, connect it in four controlled steps.
Contact Support with the company, integration purpose, technical contact, and data access required.
An AppyShift Super Admin provisions a named client with approved scopes. Capture the one-time client secret securely.
Request a token, then call /api/v1/capabilities to confirm the tenant, expiry, scopes, and available operations.
Read workforce resources, run an approved report, perform permitted writes, or receive signed webhook events.
Continue to endpoint examplesEach endpoint keeps its request, response, and schema references together.
These rules apply across the protected REST API unless an endpoint documents a narrower limit or a different response field.
curl --request GET \
"https://www.appyshift.com/acme/api/v1/employees?limit=100" \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Accept: application/json"
{
"data": [
{"id": 42, "name": "Jordan Lee"}
],
"meta": {
"request_id": "req_7c85c8f31e0a",
"row_count": 1,
"pagination": {
"applied": true,
"limit": 100,
"has_more": false,
"next_after_id": null
}
}
}
Protected endpoints return UTF-8 JSON. Send Accept: application/json on reads and Content-Type: application/json for JSON writes. The OAuth token exchange is the form-encoded exception.
Accept: application/json Use the client-credentials grant from server-side code. Access tokens last up to 3,600 seconds, carry a granted scope subset, and must be replaced through /oauth/token rather than refreshed.
Authorization: Bearer {access_token} The company slug in the URL and the OAuth client tenant must agree. Credentials issued for one company cannot be used to cross into another company portal.
/{company_slug}/api/v1/... Protected success responses use data for resource output and meta for request context when applicable. Every protected API operation includes a request_id in its success metadata or error object.
meta.request_id Use each schema’s required and nullable flags. Dates use YYYY-MM-DD; timestamp and formatted report values follow the field-level contract rather than one inferred display format.
YYYY-MM-DD Omitted custom fields remain unchanged. Null or an empty scalar clears an optional custom field; required fields cannot be cleared. One request can submit at most 100 fields.
PATCH /employees/{id}/fields Pagination is endpoint-specific. The employee roster enables cursor mode with limit or after_id, returns at most 500 rows, and advertises has_more plus next_after_id in meta.pagination.
?limit=100&after_id=42 Protected errors return error.code, error.message, and error.request_id. OAuth token failures use the OAuth error and error_description shape instead.
error.request_id Per API client across its active access tokens
Per source IP within a company portal
Per minute and source IP
Maximum raw body accepted for an API write
HTTP 429 is the stable signal today. Use bounded exponential backoff with jitter; Retry-After and remaining-quota headers are not currently guaranteed.
| Operation | Policy | Guidance |
|---|---|---|
| GET resources and catalogs | Safe to retry | Repeat the same request after a temporary failure. Preserve filters and use the returned cursor for the next page. |
| POST /api/v1/reports/run | Read-only execution | A retry does not mutate workforce records, but it creates another access-log entry and consumes rate-limit capacity. |
| PATCH employee fields | Read back first | If the response is lost, retrieve the employee field values before retrying. Repeated writes can create additional audit activity. |
| Webhook deliveries | Deduplicate | Store X-AppyShift-Delivery as the idempotency key. REST writes do not currently accept a generic Idempotency-Key header. |
All API paths below are appended to the company-specific base URL. They are grouped by function.
/oauth/tokenExchange a client ID and one-time client secret for a short-lived bearer token.
curl --request POST \
https://www.appyshift.com/acme/oauth/token \
--user "aps_client_xxx:aps_secret_xxx" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=employee_fields:read reports:read reports:run"
{
"access_token": "aps_oauth_xxx",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "employee_fields:read reports:read reports:run"
}
/api/v1/capabilitiesReturns the current company, authentication type, granted scopes, expiry information, and only the operations this token can call.
curl \
https://www.appyshift.com/acme/api/v1/capabilities \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"api_version": "v1",
"company_slug": "acme",
"client": {
"name": "Payroll warehouse",
"authentication": "oauth2",
"scopes": ["employees:read", "timesheets:read"],
"token_expires_at": "2026-08-20 16:30:00",
"client_expires_at": null
},
"operations": [
{"method": "GET", "path": "/api/v1/capabilities", "required_scopes": []},
{"method": "GET", "path": "/api/v1/employees", "required_scopes": ["employees:read"]},
{"method": "GET", "path": "/api/v1/timesheets", "required_scopes": ["timesheets:read"]}
]
},
"meta": {"request_id": "req_xxx", "operation_count": 3}
}
/api/v1/employeesReturns the employee roster with status, department, position, payroll identifier, and updated timestamp.
curl --get \
https://www.appyshift.com/acme/api/v1/employees \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=ACTIVE" \
--data-urlencode "updated_since=2026-08-01T00:00:00Z" \
--data-urlencode "limit=100"
{
"data": [
{
"id": 42,
"name": "Jordan Lee",
"email": "jordan.lee@example.com",
"payroll_id": "EE-1042",
"department_id": 7,
"department": "Front Desk",
"position_id": 12,
"job_title": "Guest Services Lead",
"pay_type": "HOURLY",
"status": "ACTIVE",
"active": true,
"updated_at": "2026-08-18 14:22:09"
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"pagination": {
"applied": true,
"limit": 100,
"has_more": false,
"next_after_id": null
}
}
}
/api/v1/employees/{employee_id}Returns one employee’s standard non-sensitive profile and organization relationships.
curl \
https://www.appyshift.com/acme/api/v1/employees/42 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 42,
"first_name": "Jordan",
"last_name": "Lee",
"preferred_name": "Jordy",
"name": "Jordan Lee",
"email": "jordan.lee@example.com",
"phone": "555-123-4567",
"status": "ACTIVE",
"employment_type": "FULL_TIME",
"department_id": 7,
"department": "Front Desk",
"position_id": 12,
"position": "Guest Services Lead",
"manager_id": 9,
"manager": "Morgan Ellis",
"hire_date": "2026-05-01",
"termination_date": "",
"location": "Main Office",
"payroll_id": "EE-1042",
"portal_enabled": true,
"created_at": "2026-04-20 09:13:00",
"updated_at": "2026-08-18 14:22:09"
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/employees/{employee_id}/fieldsReturns selected reportable values using the same formats advertised by the employee-field catalog.
curl --get \
https://www.appyshift.com/acme/api/v1/employees/42/fields \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "fields=employee_name,hire_date,custom_17" \
--data-urlencode "formats[employee_name]=last_first" \
--data-urlencode "formats[hire_date]=us"
{
"data": {
"employee_id": 42,
"values": {
"employee_last_first": "Lee, Jordan",
"hire_date_us": "05/01/2026",
"custom_17": "Large"
}
},
"meta": {
"request_id": "req_xxx",
"field_count": 3,
"fields": [
{"field": "employee_name", "output_field": "employee_last_first", "label": "Employee", "format": "last_first", "sensitive": false},
{"field": "hire_date", "output_field": "hire_date_us", "label": "Hire Date", "format": "us", "sensitive": false},
{"field": "custom_17", "output_field": "custom_17", "label": "Uniform Size", "format": "default", "sensitive": false}
],
"sensitive_fields_included": false
}
}
/api/v1/employees/{employee_id}/fieldsPartially updates active, reportable custom fields. Omitted fields remain unchanged.
curl --request PATCH \
https://www.appyshift.com/acme/api/v1/employees/42/fields \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"values": {
"custom_17": "Extra Large",
"custom_24": "2026-09-30",
"custom_31": true
}
}'
{
"data": {
"employee_id": 42,
"values": {
"custom_17": "Extra Large",
"custom_24": "2026-09-30",
"custom_31": "1"
}
},
"meta": {
"request_id": "req_xxx",
"changed_fields": ["custom_17", "custom_24", "custom_31"]
}
}
/api/v1/employee-fieldsReturns reportable system and custom field definitions, choice options, and supported output formats.
curl \
https://www.appyshift.com/acme/api/v1/employee-fields \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [
{
"key": "employee_name",
"label": "Employee",
"group": "Identity",
"source": "system",
"type": "system",
"custom_field_id": null,
"writable": false,
"required": false,
"options": [],
"available_on_roster": true,
"sensitive": false,
"formats": [
{"key": "default", "label": "First Last", "output_field": "employee_name"},
{"key": "last_first", "label": "Last, First", "output_field": "employee_last_first"}
]
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"sensitive_fields_included": false
}
}
/api/v1/credentialsReturns employee certifications and licenses with issue, expiry, verification, and status information.
curl --get \
https://www.appyshift.com/acme/api/v1/credentials \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=ACTIVE" \
--data-urlencode "expiring_within_days=60"
{
"data": [{
"id": 91,
"employee_id": 42,
"employee_name": "Jordan Lee",
"employee_payroll_id": "EE-1042",
"certification_name": "Food Handler",
"credential_number": "FH-10293",
"issued_at": "2026-01-10",
"expires_at": "2027-01-10",
"status": "ACTIVE",
"notes": "",
"verified_at": "2026-01-11 10:00:00"
}],
"meta": {"request_id": "req_xxx", "row_count": 1}
}
/api/v1/departmentsReturns departments with descriptions, display colors, and active employee counts.
curl https://www.appyshift.com/acme/api/v1/departments \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [{"id": 7, "name": "Front Desk", "description": "Guest arrival team", "color": "#2563eb", "employee_count": 12}],
"meta": {"request_id": "req_xxx", "row_count": 1}
}
/api/v1/positionsReturns job positions with descriptions, department names, and active employee counts.
curl https://www.appyshift.com/acme/api/v1/positions \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [{"id": 12, "title": "Guest Services Lead", "description": "Leads guest arrival operations", "department_name": "Front Desk", "employee_count": 3}],
"meta": {"request_id": "req_xxx", "row_count": 1}
}
/api/v1/locationsReturns work-location addresses, coordinates, geofence settings, status, and active employee counts.
curl https://www.appyshift.com/acme/api/v1/locations \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [{
"id": 3,
"name": "Main Office",
"address": "100 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701",
"lat": 30.2672,
"lon": -97.7431,
"is_active": true,
"geofence_radius_feet": 500,
"employee_count": 18
}],
"meta": {"request_id": "req_xxx", "row_count": 1}
}
/api/v1/timesheetsReturns completed clock-in and clock-out entries for a required date range.
curl --get \
https://www.appyshift.com/acme/api/v1/timesheets \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "start_date=2026-08-01" \
--data-urlencode "end_date=2026-08-14"
{
"data": [{
"id": 8221,
"employee_id": 42,
"employee_name": "Jordan Lee",
"employee_payroll_id": "EE-1042",
"work_date": "2026-08-03",
"clock_in": "2026-08-03 08:02:00",
"clock_out": "2026-08-03 16:31:00",
"hours": 8.0167,
"entry_type": "MOBILE",
"notes": ""
}],
"meta": {"request_id": "req_xxx", "start_date": "2026-08-01", "end_date": "2026-08-14", "row_count": 1}
}
/api/v1/schedulesReturns employee shift assignments, times, status, position, department, location, and notes for a required date range.
curl --get \
https://www.appyshift.com/acme/api/v1/schedules \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "start_date=2026-08-17" \
--data-urlencode "end_date=2026-08-23"
{
"data": [{
"id": 5512,
"employee_id": 42,
"employee_name": "Jordan Lee",
"employee_payroll_id": "EE-1042",
"shift_date": "2026-08-18",
"start_time": "08:00:00",
"end_time": "16:00:00",
"status": "PUBLISHED",
"location": "Main Office",
"notes": "",
"position_title": "Guest Services Lead",
"department_name": "Front Desk"
}],
"meta": {"request_id": "req_xxx", "start_date": "2026-08-17", "end_date": "2026-08-23", "row_count": 1}
}
/api/v1/time-offReturns time-off requests for a date range or employee leave balances for a year.
curl --get \
https://www.appyshift.com/acme/api/v1/time-off \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "view=requests" \
--data-urlencode "start_date=2026-08-01" \
--data-urlencode "end_date=2026-09-30" \
--data-urlencode "employee_id=42"
{
"data": [{
"id": 381,
"employee_id": 42,
"employee_name": "Jordan Lee",
"employee_payroll_id": "EE-1042",
"type": "VACATION",
"start_date": "2026-09-08",
"end_date": "2026-09-10",
"status": "APPROVED",
"reason": "Family trip",
"reviewed_at": "2026-08-20 11:10:00",
"review_notes": "Approved",
"created_at": "2026-08-19 09:25:00"
}],
"meta": {"request_id": "req_xxx", "view": "requests", "start_date": "2026-08-01", "end_date": "2026-09-30", "row_count": 1}
}
/api/v1/employees/{employee_id}/payroll-idAssigns or clears the external payroll identifier for one employee.
curl --request POST \
https://www.appyshift.com/acme/api/v1/employees/42/payroll-id \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{"payroll_id":"EE-1042"}'
{
"data": {
"id": 42,
"name": "Jordan Lee",
"email": "jordan.lee@example.com",
"payroll_id": "EE-1042",
"active": true
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/deductionsReturns active deduction elections, employee amounts, and employer matching values.
curl --get \
https://www.appyshift.com/acme/api/v1/deductions \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "employee_id=42"
{
"data": [{
"employee_id": 42,
"employee_name": "Jordan Lee",
"employee_payroll_id": "EE-1042",
"code": "MEDICAL",
"label": "Medical Plan",
"deduction_type": "PRE_TAX",
"employee_amount": 85.25,
"employer_match": 50
}],
"meta": {"request_id": "req_xxx", "row_count": 1}
}
/api/v1/payroll/runsReturns approved, payment staged and paid payroll runs with their pay period, pay date and company totals: gross pay, employee and employer taxes, deductions and net pay.
curl --get \
https://www.appyshift.com/acme/api/v1/payroll/runs \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "pay_date_from=2026-07-01" \
--data-urlencode "pay_date_to=2026-09-30" \
--data-urlencode "limit=50"
{
"data": [
{
"id": 318,
"run_code": "PAY-20260816-20260831-A1B2C3",
"label": "Aug 16 – 31, 2026",
"run_type": "REGULAR",
"status": "PAID",
"period_start": "2026-08-16",
"period_end": "2026-08-31",
"pay_date": "2026-09-04",
"employee_count": 18,
"gross_pay": 42810.55,
"employee_taxes": 6120.4,
"employer_taxes": 3488.12,
"deductions": 2210,
"net_pay": 34480.15,
"approved_at": "2026-09-02 15:41:09",
"paid_at": "2026-09-04 09:02:44",
"voided_at": null,
"correction": false,
"void_reversal": false,
"voided_statement_count": 0
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"statuses": ["APPROVED", "PAYMENT_STAGED", "PAID"],
"include_unapproved": false,
"pay_date_from": "2026-07-01",
"pay_date_to": "2026-09-30",
"pagination": {"limit": 50, "has_more": false, "next_after_id": null}
}
}
/api/v1/payroll/runs/{run_id}Returns one payroll run with its totals by earning code, deduction code and tax. No line names an employee.
curl \
https://www.appyshift.com/acme/api/v1/payroll/runs/318 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 318,
"run_code": "PAY-20260816-20260831-A1B2C3",
"label": "Aug 16 – 31, 2026",
"run_type": "REGULAR",
"status": "PAID",
"period_start": "2026-08-16",
"period_end": "2026-08-31",
"pay_date": "2026-09-04",
"employee_count": 18,
"gross_pay": 42810.55,
"employee_taxes": 6120.4,
"employer_taxes": 3488.12,
"deductions": 2210,
"net_pay": 34480.15,
"approved_at": "2026-09-02 15:41:09",
"paid_at": "2026-09-04 09:02:44",
"voided_at": null,
"correction": false,
"void_reversal": false,
"voided_statement_count": 0,
"statement_count": 18,
"hours": 1462.5,
"earnings_by_code": [
{"code": "REG", "label": "Regular Pay", "type": "REGULAR", "hours": 1380, "amount": 39960.55, "statement_count": 18},
{"code": "OT", "label": "Overtime Pay", "type": "OVERTIME", "hours": 82.5, "amount": 2850, "statement_count": 6}
],
"deductions_by_code": [
{"code": "K401", "label": "401(k)", "type": "PRE_TAX", "employee_amount": 2210, "employer_amount": 0, "statement_count": 11}
],
"taxes_by_tax": [
{"name": "Federal income tax", "code": "FIT", "scope": "FEDERAL", "jurisdiction": "US", "taxable_wages": 40600.55, "employee_amount": 3105.17, "employer_amount": 0},
{"name": "Social Security", "code": "SS", "scope": "FICA", "jurisdiction": "US", "taxable_wages": 40600.55, "employee_amount": 2517.23, "employer_amount": 2517.23}
]
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/payroll/runs/{run_id}/statementsReturns each employee's pay statement on the run: earnings with hours and rates, deductions, taxes, net pay, the payment method and check number. Never Social Security numbers, addresses or bank details.
curl --get \
https://www.appyshift.com/acme/api/v1/payroll/runs/318/statements \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "limit=100"
{
"data": [
{
"id": 90412,
"run_id": 318,
"employee_id": 42,
"employee_payroll_id": "EE-1042",
"employee_name": "Jordan Lee",
"department": "Front Desk",
"hours": 80,
"gross_pay": 1760,
"pre_tax_deductions": 50,
"post_tax_deductions": 0,
"employee_taxes": 290.48,
"employer_taxes": 134.64,
"net_pay": 1419.52,
"payment_method": "ACH",
"check_number": null,
"voided": false,
"void_reversal": false,
"earnings": [
{"code": "REG", "label": "Regular Pay", "type": "REGULAR", "hours": 80, "rate": 22, "effective_rate": 22, "amount": 1760, "taxable": true, "non_cash": false}
],
"deductions": [
{"code": "K401", "label": "401(k)", "type": "PRE_TAX", "employee_amount": 50, "employer_amount": 0}
],
"taxes": [
{"name": "Federal income tax", "code": "FIT", "scope": "FEDERAL", "jurisdiction": "US", "taxable_wages": 1710, "employee_amount": 155.84, "employer_amount": 0},
{"name": "Social Security", "code": "SS", "scope": "FICA", "jurisdiction": "US", "taxable_wages": 1760, "employee_amount": 109.12, "employer_amount": 109.12},
{"name": "Medicare", "code": "MED", "scope": "MEDICARE", "jurisdiction": "US", "taxable_wages": 1760, "employee_amount": 25.52, "employer_amount": 25.52}
]
}
],
"meta": {
"request_id": "req_xxx",
"run_id": 318,
"run_status": "PAID",
"row_count": 1,
"pagination": {"limit": 100, "has_more": false, "next_after_id": null}
}
}
/api/v1/payroll/tax-liabilitiesReturns tax liability by tax and jurisdiction for payrolls paid in a quarter, the way the Taxes section adds it up, with the payrolls included.
curl --get \
https://www.appyshift.com/acme/api/v1/payroll/tax-liabilities \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "year=2026" \
--data-urlencode "quarter=3"
{
"data": {
"year": 2026,
"quarter": 3,
"period_start": "2026-07-01",
"period_end": "2026-09-30",
"lines": [
{"code": "FIT", "tax": "Federal income tax", "jurisdiction": "US", "taxable_wages": 121801.65, "employee_amount": 9315.51, "employer_amount": 0, "total": 9315.51, "employee_count": 18, "lines_changed_by_hand": 0},
{"code": "SS", "tax": "Social Security", "jurisdiction": "US", "taxable_wages": 128431.65, "employee_amount": 7962.76, "employer_amount": 7962.76, "total": 15925.52, "employee_count": 18, "lines_changed_by_hand": 0}
],
"totals": {"employee_amount": 17278.27, "employer_amount": 7962.76, "total": 25241.03},
"statement_count": 54,
"employee_count": 18,
"payrolls": [
{"run_id": 318, "run_code": "PAY-20260816-20260831-A1B2C3", "label": "Aug 16 – 31, 2026", "status": "PAID", "pay_date": "2026-09-04", "employee_taxes": 6120.4, "employer_taxes": 3488.12, "federal_deposit_taxes": 8721.6}
]
},
"meta": {"request_id": "req_xxx", "include_unapproved": false, "warnings": []}
}
/api/v1/payroll/tax-depositsReturns each tax deposit due for a quarter (federal, state, local, SUI and contributions) and the year's FUTA deposits, with the amount the company recorded as deposited, the balance and the status.
curl --get \
https://www.appyshift.com/acme/api/v1/payroll/tax-deposits \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "year=2026" \
--data-urlencode "quarter=3"
{
"data": {
"year": 2026,
"quarter": 3,
"period_start": "2026-07-01",
"period_end": "2026-09-30",
"filer_form": "941",
"deposit_schedule": "MONTHLY",
"deposits": [
{
"kind": "941",
"tax": "Federal payroll taxes (Form 941)",
"jurisdiction": "US",
"period_start": "2026-08-01",
"period_end": "2026-08-31",
"rule": "MONTHLY",
"due_date": "2026-09-15",
"amount": 8721.6,
"recorded": 8721.6,
"balance": 0,
"status": "scheduled",
"status_label": "Scheduled for Sep 14",
"next_day": false,
"breakdown": []
}
]
},
"meta": {"request_id": "req_xxx", "as_of": "2026-09-10", "row_count": 1, "warnings": []}
}
/api/v1/payroll/general-ledgerReturns the payroll journal the General ledger detail report produces: one entry per approved or paid payroll, dated on its pay date, with lines by account, department and memo.
curl --get \
https://www.appyshift.com/acme/api/v1/payroll/general-ledger \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "pay_date_from=2026-09-01" \
--data-urlencode "pay_date_to=2026-09-30"
{
"data": [
{
"run_id": 318,
"run_code": "PAY-20260816-20260831-A1B2C3",
"label": "Aug 16 – 31, 2026",
"run_type": "REGULAR",
"entry_date": "2026-09-04",
"total_debit": 46298.67,
"total_credit": 46298.67,
"balanced": true,
"lines": [
{"account": "6000", "account_name": "Wages Expense", "department": "Front Desk", "memo": "Earnings: Regular Pay (REG)", "debit": 12410, "credit": 0, "mapped": true, "default_account": false},
{"account": "2100", "account_name": "Wages Payable", "department": "Front Desk", "memo": "Net pay: Direct deposit", "debit": 0, "credit": 9988.2, "mapped": true, "default_account": true}
]
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"run_id": null,
"pay_date_from": "2026-09-01",
"pay_date_to": "2026-09-30",
"totals": {"debit": 46298.67, "credit": 46298.67, "difference": 0, "balanced": true, "unmapped_amount": 0, "unmapped_lines": 0}
}
}
/api/v1/reportsReturns saved report definitions and the datasets and columns available to the token.
curl \
https://www.appyshift.com/acme/api/v1/reports \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [
{
"id": 18,
"name": "Active employee roster",
"description": "Current employees for payroll review",
"dataset": "employee_roster",
"columns": ["employee_name", "department", "hire_date"],
"column_formats": {"employee_name": "last_first", "hire_date": "us"},
"filters": {"status": "ACTIVE"},
"updated_at": "2026-08-18 11:45:00"
}
],
"datasets": {
"employee_roster": {
"label": "Employee roster",
"date_enabled": false,
"default_columns": ["employee_name", "department", "position"],
"columns": {
"employee_name": {"label": "Employee", "sensitive": false}
}
}
},
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"sensitive_fields_included": false
}
}
/api/v1/reports/runRuns a saved report by report_id or an ad-hoc report using a dataset, columns, formats, labels, and filters.
curl --request POST \
https://www.appyshift.com/acme/api/v1/reports/run \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"dataset": "employee_roster",
"columns": ["employee_name", "department", "hire_date"],
"column_formats": {
"employee_name": "last_first",
"hire_date": "us"
},
"filters": {"status": "ACTIVE"},
"metadata": {
"workflow_run_id": "sync_2026_08_19_001",
"destination": "payroll"
}
}'
{
"data": [
{
"employee_last_first": "Lee, Jordan",
"department": "Front Desk",
"hire_date_us": "05/01/2026"
}
],
"meta": {
"request_id": "req_xxx",
"report_id": null,
"dataset": "employee_roster",
"row_count": 1,
"columns": [
{"key": "employee_last_first", "label": "Employee"},
{"key": "department", "label": "Department"},
{"key": "hire_date_us", "label": "Hire Date"}
],
"sensitive_fields_included": false,
"client_metadata": {
"workflow_run_id": "sync_2026_08_19_001",
"destination": "payroll"
}
}
}
/api/v1/recognition/shout-outsReturns shout-outs from the company's Recognition feed, oldest first: who sent it, who was recognized, the message, the value and the points it carried.
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/shout-outs \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "created_from=2026-10-01" \
--data-urlencode "limit=100"
{
"data": [
{
"id": 5120,
"created_at": "2026-10-16 09:12:44",
"status": "PUBLISHED",
"visibility": "everyone",
"from": {"type": "employee", "employee_id": 42, "name": "Avery Stone"},
"to_employees": [{"id": 57, "name": "Jordan Lee"}],
"message": "Covered my Saturday close on short notice.",
"value": {"key": "COVERED_SHIFT", "label": "Covered a shift"},
"points_awarded": 20,
"points_pending": 0
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"pagination": {"limit": 100, "has_more": false, "next_after_id": null}
}
}
/api/v1/recognition/shout-outsRecognizes one or more coworkers, with the same rules as the app: one board post per coworker, the coworker is told, an employee's post waits for a manager when the company asks for that, and points come from the sender's monthly bank or the company's manager and customer awards.
curl --request POST \
https://www.appyshift.com/acme/api/v1/recognition/shout-outs \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"to_employee_ids": [57],
"from_employee_id": 42,
"message": "Covered my Saturday close on short notice.",
"value": "COVERED_SHIFT",
"points": 20
}'
{
"data": [
{
"id": 5121,
"created_at": "2026-10-16 09:30:02",
"status": "PUBLISHED",
"visibility": "everyone",
"from": {"type": "employee", "employee_id": 42, "name": "Avery Stone"},
"to_employees": [{"id": 57, "name": "Jordan Lee"}],
"message": "Covered my Saturday close on short notice.",
"value": {"key": "COVERED_SHIFT", "label": "Covered a shift"},
"points_awarded": 20,
"points_pending": 0
}
],
"meta": {"request_id": "req_xxx", "created_count": 1}
}
/api/v1/recognition/pointsReturns each employee's points: earned, redeemed for rewards, available to spend, and pending approval.
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/points \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "limit=100"
{
"data": [
{"employee": {"id": 57, "name": "Jordan Lee"}, "earned": 145, "redeemed": 100, "available": 45, "pending": 0}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"pagination": {"limit": 100, "has_more": false, "next_after_id": null},
"points_enabled": true
}
}
/api/v1/recognition/badgesReturns the badge catalog with each badge's tiers, or with employee_id, that employee's progress on every badge. Badges are earned from real records (pickups, coverage, attendance, anniversaries, shout-outs).
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/badges \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [
{"key": "shift_saver", "name": "Shift Saver", "emoji": "🛟", "tiers": [1, 5, 10, 25], "unit": "called-out shifts picked up", "unit_one": "called-out shift picked up"}
],
"meta": {"request_id": "req_xxx", "row_count": 1, "badges_enabled": true}
}
/api/v1/recognition/rewardsReturns the company's rewards store: each reward's point price, type (ITEM, CASH or PTO), value and stock.
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/rewards \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [
{"id": 12, "name": "$25 gift card", "description": "", "points_cost": 250, "type": "CASH", "cash_value": 25, "pto_hours": null, "stock": null, "active": true, "has_picture": true, "created_at": "2026-10-12 14:02:11"}
],
"meta": {"request_id": "req_xxx", "row_count": 1, "rewards_store_open": true}
}
/api/v1/recognition/redemptionsReturns employees' reward requests and what a manager decided. CASH rewards are paid as taxable pay through payroll when fulfilled.
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/redemptions \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=requested"
{
"data": [
{
"id": 88,
"employee": {"id": 57, "name": "Jordan Lee"},
"reward": {"id": 12, "name": "$25 gift card", "type": "CASH"},
"points": 250,
"cash_value": 25,
"pto_hours": null,
"status": "REQUESTED",
"requested_at": "2026-10-15 17:40:03",
"decided_at": null,
"decided_by_name": null,
"note": ""
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"pagination": {"limit": 100, "has_more": false, "next_after_id": null}
}
}
/api/v1/recognition/valuesReturns what a shout-out can recognize (Teamwork, Covered a shift and so on): the keys POST /api/v1/recognition/shout-outs accepts as value.
curl --get \
https://www.appyshift.com/acme/api/v1/recognition/values \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": [
{"key": "TEAMWORK", "label": "Teamwork"},
{"key": "COVERED_SHIFT", "label": "Covered a shift"}
],
"meta": {"request_id": "req_xxx", "row_count": 2}
}
/api/v1/jobsReturns the company's job openings with status, position, department, location, employment type, posted and closed dates, the pay range when the posting shows it, and the public careers link for open jobs.
curl --get \
https://www.appyshift.com/acme/api/v1/jobs \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=OPEN" \
--data-urlencode "limit=50"
{
"data": [
{
"id": 18,
"title": "Line Cook",
"status": "OPEN",
"employment_type": "FULL_TIME",
"workplace_type": "ONSITE",
"openings": 2,
"position": { "id": 4, "title": "Cook" },
"department": { "id": 7, "name": "Kitchen" },
"location": { "work_location_id": 3, "name": "Downtown", "city": "Austin", "state": "TX" },
"pay": { "min": 18, "max": 22, "period": "HOUR", "currency": "USD", "extras": ["TIPS"], "display": "$18 - $22 / hour + tips" },
"posted_at": "2026-10-01 08:00:00",
"closed_at": null,
"created_at": "2026-09-29 15:20:00",
"updated_at": "2026-10-01 08:00:00",
"careers_url": "https://www.appyshift.com/acme/careers/line-cook"
}
],
"meta": { "request_id": "req_xxx", "row_count": 1, "limit": 50, "has_more": false, "next_after_id": null }
}
/api/v1/applicantsReturns applications oldest first: name, email, phone, stage, source and dates. A token with applicants.sensitive:read also gets each applicant's details.
curl --get \
https://www.appyshift.com/acme/api/v1/applicants \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "job_id=18" \
--data-urlencode "stage=INTERVIEW" \
--data-urlencode "updated_since=2026-10-01T00:00:00Z"
{
"data": [
{
"id": 5012,
"candidate_id": 3307,
"job_id": 18,
"job_title": "Line Cook",
"first_name": "Pat",
"last_name": "Lee",
"email": "pat.lee@example.com",
"phone": "555-123-4567",
"stage": "INTERVIEW",
"stage_label": "Interview",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 09:12:00",
"updated_at": "2026-10-15 16:40:00"
}
],
"meta": { "request_id": "req_xxx", "row_count": 1, "limit": 100, "has_more": false, "next_after_id": null, "includes_details": false }
}
/api/v1/applicants/{applicant_id}Returns one applicant with its stage history and interview times. With applicants.sensitive:read: details and the team's notes.
curl https://www.appyshift.com/acme/api/v1/applicants/5012 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 5012,
"candidate_id": 3307,
"job_id": 18,
"job_title": "Line Cook",
"first_name": "Pat",
"last_name": "Lee",
"email": "pat.lee@example.com",
"phone": "555-123-4567",
"stage": "INTERVIEW",
"stage_label": "Interview",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 09:12:00",
"updated_at": "2026-10-15 16:40:00",
"stage_history": [
{ "stage": "NEW", "changed_at": "2026-10-14 09:12:00" },
{ "stage": "INTERVIEW", "changed_at": "2026-10-15 16:40:00" }
],
"interviews": [
{ "id": 77, "status": "BOOKED", "location_type": "IN_PERSON", "starts_at_utc": "2026-10-17 15:00:00", "ends_at_utc": "2026-10-17 15:30:00" }
]
},
"meta": { "request_id": "req_xxx", "includes_details": false }
}
/api/v1/applicantsAdds an application from an external job board or form, with the careers page's rules: an open job, first and last name, phone, a valid email, and one application per email per job. Answers 201 with the new applicant.
curl --request POST \
https://www.appyshift.com/acme/api/v1/applicants \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"job_id": 18,
"first_name": "Pat",
"last_name": "Lee",
"email": "pat.lee@example.com",
"phone": "555-123-4567",
"source": "Indeed"
}'
{
"data": {
"id": 5012,
"candidate_id": 3307,
"job_id": 18,
"job_title": "Line Cook",
"first_name": "Pat",
"last_name": "Lee",
"email": "pat.lee@example.com",
"phone": "555-123-4567",
"stage": "NEW",
"stage_label": "New",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 09:12:00",
"updated_at": "2026-10-14 09:12:00",
"stage_history": [{ "stage": "NEW", "changed_at": "2026-10-14 09:12:00" }],
"interviews": []
},
"meta": { "request_id": "req_xxx", "new_candidate": true, "includes_details": false }
}
/api/v1/applicants/{applicant_id}Moves the applicant to another stage, adds a note, or both, with the Applicants screen's rules. Hiring happens in AppyShift with Hire & set up employee, so HIRED is accepted only for a candidate who already has an employee record.
curl --request PATCH \
https://www.appyshift.com/acme/api/v1/applicants/5012 \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"stage": "DECLINED",
"decline_reason": "SCHEDULE",
"note": "Needs weekends off; we need weekend coverage.",
"expected_updated_at": "2026-10-15 16:40:00"
}'
{
"data": {
"id": 5012,
"candidate_id": 3307,
"job_id": 18,
"job_title": "Line Cook",
"first_name": "Pat",
"last_name": "Lee",
"email": "pat.lee@example.com",
"phone": "555-123-4567",
"stage": "DECLINED",
"stage_label": "Declined",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 09:12:00",
"updated_at": "2026-10-16 10:05:00",
"stage_history": [
{ "stage": "NEW", "changed_at": "2026-10-14 09:12:00" },
{ "stage": "DECLINED", "changed_at": "2026-10-16 10:05:00" }
],
"interviews": []
},
"meta": { "request_id": "req_xxx", "changed": true, "note_added": true, "previous_stage": "INTERVIEW", "includes_details": false }
}
/api/v1/announcementsReturns the company's announcements (scheduled, active and expired) with the plain-text body, audience, publish and expiry times, author, and acknowledgement and read counts.
curl --get \
https://www.appyshift.com/acme/api/v1/announcements \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "published_from=2026-10-01" \
--data-urlencode "published_to=2026-10-31" \
--data-urlencode "limit=100"
{
"data": [{
"id": 318,
"title": "Holiday hours",
"body": "The store closes at 3 PM on Friday.\n\n- Morning shifts start as usual\n- Close by 3:30",
"priority": "HIGH",
"audience": {"type": "department", "department_id": 4, "department_name": "Kitchen"},
"status": "active",
"published_at": "2026-10-16 09:00:00",
"expires_at": "2026-10-24 23:59:59",
"author": {"user_id": 7, "name": "Pat Morgan"},
"requires_acknowledgement": true,
"acknowledged_count": 14,
"audience_count": 22,
"read_count": 19,
"created_at": "2026-10-15 16:42:10"
}],
"meta": {
"request_id": "req_xxx",
"timezone": "America/Chicago",
"row_count": 1,
"limit": 100,
"has_more": false,
"next_after_id": null
}
}
/api/v1/announcements/{announcement_id}Returns one announcement of this company. Another company's ID answers 404 announcement_not_found.
curl https://www.appyshift.com/acme/api/v1/announcements/318 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 318,
"title": "Holiday hours",
"body": "The store closes at 3 PM on Friday.",
"priority": "HIGH",
"audience": {"type": "everyone"},
"status": "active",
"published_at": "2026-10-16 09:00:00",
"expires_at": null,
"author": {"user_id": 7, "name": "Pat Morgan"},
"requires_acknowledgement": false,
"acknowledged_count": null,
"audience_count": 58,
"read_count": 41,
"created_at": "2026-10-15 16:42:10"
},
"meta": {"request_id": "req_xxx", "timezone": "America/Chicago"}
}
/api/v1/announcementsPosts an announcement to the employee app, the same way the Announcements page does: to everyone or one department, now or at publish_at, optionally by push notification and email to everyone it is for. The audit log names the API client, and the announcement.published webhook fires.
curl --request POST \
https://www.appyshift.com/acme/api/v1/announcements \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"title": "Inventory count Sunday",
"body": "Please plan to stay 30 minutes after close.\n\nThanks!",
"priority": "NORMAL",
"audience": {"type": "department", "department_id": 4},
"publish_at": "2026-10-17T08:00:00",
"expires_at": "2026-10-20",
"require_acknowledgement": true,
"deliver": ["push", "email"]
}'
{
"data": {
"id": 319,
"title": "Inventory count Sunday",
"body": "Please plan to stay 30 minutes after close.\n\nThanks!",
"priority": "NORMAL",
"audience": {"type": "department", "department_id": 4, "department_name": "Kitchen"},
"status": "scheduled",
"published_at": "2026-10-17 08:00:00",
"expires_at": "2026-10-20 23:59:59",
"author": null,
"requires_acknowledgement": true,
"acknowledged_count": 0,
"audience_count": 22,
"read_count": 0,
"created_at": "2026-10-16 10:12:44"
},
"meta": {
"request_id": "req_xxx",
"timezone": "America/Chicago",
"delivery": {"requested": ["push", "email"], "queued": ["push", "email"], "message": null}
}
}
/api/v1/surveysReturns the company's surveys with question counts and participation (assigned, completed, response rate).
curl --get \
https://www.appyshift.com/acme/api/v1/surveys \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "active=true"
{
"data": [{
"id": 12,
"title": "Quarterly pulse",
"description": "Five quick questions about your work week.",
"active": true,
"question_count": 5,
"assigned_count": 40,
"completed_count": 31,
"response_rate": 78,
"created_at": "2026-10-01 08:30:00"
}],
"meta": {"request_id": "req_xxx", "row_count": 1, "limit": 100, "has_more": false, "next_after_id": null}
}
/api/v1/surveys/{survey_id}/resultsReturns a survey's results as counts only: answers per choice, the rating average and spread, yes and no, and how many people answered each written question. The API never returns who answered, one person's answers, or written answers.
curl https://www.appyshift.com/acme/api/v1/surveys/12/results \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 12,
"title": "Quarterly pulse",
"description": "Five quick questions about your work week.",
"active": true,
"assigned_count": 40,
"completed_count": 31,
"response_rate": 78,
"questions": [
{"id": 51, "text": "Which shift do you prefer?", "type": "multiple_choice", "required": true, "response_count": 31,
"options": [{"id": 140, "text": "Morning", "count": 18}, {"id": 141, "text": "Evening", "count": 13}]},
{"id": 52, "text": "How was your week?", "type": "rating", "required": true, "response_count": 30,
"rating": {"average": 4.2, "distribution": {"1": 0, "2": 1, "3": 4, "4": 12, "5": 13}}},
{"id": 53, "text": "Do you have the tools you need?", "type": "yes_no", "required": true, "response_count": 31,
"yes_no": {"yes": 27, "no": 4}},
{"id": 54, "text": "Anything else?", "type": "text", "required": false, "response_count": 9}
]
},
"meta": {"request_id": "req_xxx", "aggregate_only": true}
}
/api/v1/onboardingOne record per employee with onboarding tasks: plan, task and form progress, Form I-9 status and e-signature status. Form answers, signature images, IP addresses, Social Security numbers, I-9 document numbers or images, bank details and uploaded files are never included.
OnboardingHire
curl --get \
https://www.appyshift.com/acme/api/v1/onboarding \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=in_progress" \
--data-urlencode "started_since=2026-08-01" \
--data-urlencode "limit=100"
{
"data": [
{
"employee_id": 42,
"name": "Jordan Lee",
"employee_status": "ACTIVE",
"start_date": "2026-08-24",
"plan_name": "Front desk onboarding",
"plans": [{"id": 3, "name": "Front desk onboarding"}],
"status": "in_progress",
"started_at": "2026-08-18 09:12:00",
"completed_at": null,
"progress": {
"tasks": {"total": 7, "completed": 5, "overdue": 1},
"forms": {"total": 3, "completed": 2}
},
"i9": {
"status": "awaiting_section_2",
"section_1_complete": true,
"section_1_completed_at": "2026-08-19 10:02:11",
"section_2_complete": false,
"section_2_completed_at": null,
"correction_requested": false
},
"e_signatures": {
"status": "pending",
"required": 4,
"signed": 2,
"awaiting_employee": 0,
"awaiting_manager": 2,
"last_signed_at": "2026-08-19 10:02:11"
}
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"pagination": {"limit": 100, "has_more": false, "next_after_id": null}
}
}
/api/v1/onboarding/{employee_id}The same record plus each task and form with its status, due date and completed date. Titles only. Form answers, signature images, IP addresses, Social Security numbers, I-9 document numbers or images, bank details and uploaded files are never included.
curl \
https://www.appyshift.com/acme/api/v1/onboarding/42 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"employee_id": 42,
"name": "Jordan Lee",
"employee_status": "ACTIVE",
"start_date": "2026-08-24",
"plan_name": "Front desk onboarding",
"plans": [{"id": 3, "name": "Front desk onboarding"}],
"status": "in_progress",
"started_at": "2026-08-18 09:12:00",
"completed_at": null,
"progress": {
"tasks": {"total": 3, "completed": 2, "overdue": 0},
"forms": {"total": 2, "completed": 1}
},
"i9": {
"status": "awaiting_section_2",
"section_1_complete": true,
"section_1_completed_at": "2026-08-19 10:02:11",
"section_2_complete": false,
"section_2_completed_at": null,
"correction_requested": false
},
"e_signatures": {
"status": "pending",
"required": 3,
"signed": 2,
"awaiting_employee": 0,
"awaiting_manager": 1,
"last_signed_at": "2026-08-19 10:02:11"
},
"tasks": [
{
"id": 812,
"title": "Read the employee handbook",
"type": "acknowledgement",
"type_label": "Guided Step",
"plan_id": 3,
"status": "completed",
"due_date": "2026-08-22",
"unlocks_on": null,
"completed_at": "2026-08-18 14:30:00",
"is_form": false,
"form": null
},
{
"id": 813,
"title": "Uniform agreement",
"type": "custom_form",
"type_label": "Custom Form",
"plan_id": 3,
"status": "completed",
"due_date": "2026-08-22",
"unlocks_on": null,
"completed_at": "2026-08-18 15:05:00",
"is_form": true,
"form": {
"kind": "pdf",
"submitted_at": "2026-08-18 15:05:00",
"employee_signature": "signed",
"employee_signed_at": "2026-08-18 15:05:00",
"manager_signature": "not_required",
"manager_signed_at": null
}
},
{
"id": 814,
"title": "Form I-9",
"type": "i9",
"type_label": "I-9 Form",
"plan_id": 3,
"status": "open",
"due_date": "2026-08-27",
"unlocks_on": null,
"completed_at": null,
"is_form": true,
"form": {
"kind": "i9",
"submitted_at": "2026-08-19 10:02:11",
"employee_signature": "signed",
"employee_signed_at": "2026-08-19 10:02:11",
"manager_signature": "pending",
"manager_signed_at": null
}
}
]
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/home-care/visitsReturns home care visits for a date range with the caregiver, scheduled times, clock-in and clock-out times, worked minutes, status and mileage, for payroll and billing reconciliation. Every visit is labelled "Home visit" and the client is an opaque client_ref: no client names, addresses, phone numbers, care details or notes are ever returned.
curl --get \
https://www.appyshift.com/acme/api/v1/home-care/visits \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "date_from=2026-10-01" \
--data-urlencode "date_to=2026-10-14" \
--data-urlencode "status=completed,missed" \
--data-urlencode "limit=100"
{
"data": [{
"id": 9101,
"label": "Home visit",
"client_ref": "hc_5f0c2a9e41b7d3386a1e2c4f",
"visit_date": "2026-10-05",
"status": "completed",
"employee": {"id": 42, "name": "Jordan Lee", "payroll_id": "EE-1042"},
"scheduled_start": "2026-10-05T09:00:00-05:00",
"scheduled_end": "2026-10-05T11:00:00-05:00",
"scheduled_minutes": 120,
"clock_in": {"at": "2026-10-05T09:04:00-05:00", "method": "time_clock", "location_check": "at_visit"},
"clock_out": {"at": "2026-10-05T11:02:00-05:00", "method": "time_clock", "location_check": "at_visit"},
"worked_minutes": 118,
"worked_hours": 1.97,
"time_status": "approved",
"mileage": {"miles": 4.2, "travel_minutes": 12, "amount": 2.94, "status": "approved"}
}],
"meta": {
"request_id": "req_xxx",
"date_from": "2026-10-01",
"date_to": "2026-10-14",
"timezone": "America/Chicago",
"row_count": 1,
"limit": 100,
"has_more": false,
"next_after_id": null
}
}
/api/v1/operations/work-ordersReturns the company's Operations work orders (jobs): status, priority, date and time window, who does it, the location or customer site, and photo and sign-off counts.
curl --get \
https://www.appyshift.com/acme/api/v1/operations/work-orders \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "status=OPEN,IN_PROGRESS" \
--data-urlencode "updated_since=2026-10-15T00:00:00-05:00" \
--data-urlencode "limit=100"
{
"data": [
{
"id": 1042,
"code": "WO-1042",
"title": "Fix the walk-in cooler door",
"description": "Door seal is torn on the left side.",
"status": "OPEN",
"priority": "HIGH",
"work_order_date": "2026-10-16",
"due_at": "2026-10-16 17:00:00",
"window_start": "2026-10-16 08:00:00",
"window_end": "2026-10-16 12:00:00",
"route_order": null,
"customer_label": null,
"location": {"id": 3, "name": "Main St"},
"site": null,
"assigned_employee": {"id": 42, "name": "Jordan Lee"},
"crew": {"id": 7, "name": "Maintenance"},
"requested_by_employee": null,
"photo_count": 0,
"signoff_count": 0,
"started_at": null,
"completed_at": null,
"completed_by": null,
"canceled_at": null,
"cancel_reason": null,
"created_at": "2026-10-16 07:12:44",
"updated_at": "2026-10-16 07:12:44"
}
],
"meta": {
"request_id": "req_xxx",
"row_count": 1,
"limit": 100,
"has_more": false,
"next_after_id": null,
"filters": {"status": ["OPEN", "IN_PROGRESS"], "updated_since": "2026-10-15 00:00:00"}
}
}
/api/v1/operations/work-orders/{work_order_id}Returns one work order with the checklist runs and incidents linked to it.
curl \
https://www.appyshift.com/acme/api/v1/operations/work-orders/1042 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 1042,
"code": "WO-1042",
"title": "Fix the walk-in cooler door",
"status": "IN_PROGRESS",
"priority": "HIGH",
"work_order_date": "2026-10-16",
"location": {"id": 3, "name": "Main St"},
"assigned_employee": {"id": 42, "name": "Jordan Lee"},
"photo_count": 2,
"signoff_count": 0,
"checklist_runs": [
{"id": 5531, "name": "Cooler check", "status": "COMPLETED", "date": "2026-10-16"}
],
"incidents": [
{"id": 88, "title": "Cooler above 41°F", "severity": "MEDIUM", "status": "RESOLVED", "incident_date": "2026-10-16"}
]
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/operations/work-ordersAdds an open work order from an external system with the same rules as the app: the employee, crew, location and site must be the company's, and the assigned employee is told in the app.
curl --request POST \
https://www.appyshift.com/acme/api/v1/operations/work-orders \
--header "Authorization: Bearer aps_oauth_xxx" \
--header "Content-Type: application/json" \
--data '{
"title": "Fix the walk-in cooler door",
"description": "Door seal is torn on the left side.",
"code": "WO-1042",
"work_order_date": "2026-10-16",
"due_at": "2026-10-16T17:00:00-05:00",
"priority": "HIGH",
"location_id": 3,
"assigned_employee_id": 42,
"crew_id": 7,
"window_start": "08:00",
"window_end": "12:00"
}'
{
"data":
{
"id": 1042,
"code": "WO-1042",
"title": "Fix the walk-in cooler door",
"description": "Door seal is torn on the left side.",
"status": "OPEN",
"priority": "HIGH",
"work_order_date": "2026-10-16",
"due_at": "2026-10-16 17:00:00",
"window_start": "2026-10-16 08:00:00",
"window_end": "2026-10-16 12:00:00",
"route_order": null,
"customer_label": null,
"location": {"id": 3, "name": "Main St"},
"site": null,
"assigned_employee": {"id": 42, "name": "Jordan Lee"},
"crew": {"id": 7, "name": "Maintenance"},
"requested_by_employee": null,
"photo_count": 0,
"signoff_count": 0,
"started_at": null,
"completed_at": null,
"completed_by": null,
"canceled_at": null,
"cancel_reason": null,
"created_at": "2026-10-16 07:12:44",
"updated_at": "2026-10-16 07:12:44"
},
"meta": {"request_id": "req_xxx", "created": true}
}
/api/v1/operations/checklistsReturns checklist runs (opening, closing, temperature logs and other checks) with completion status, item totals, items outside their limits, and who completed them.
curl --get \
https://www.appyshift.com/acme/api/v1/operations/checklists \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "from=2026-10-01" \
--data-urlencode "to=2026-10-16" \
--data-urlencode "status=COMPLETED,MISSED"
{
"data": [
{
"id": 5531,
"checklist_id": 12,
"name": "Cooler check",
"category": "TEMPERATURE",
"date": "2026-10-16",
"shift_label": "Opening",
"due_at": "2026-10-16 09:00:00",
"status": "COMPLETED",
"location": {"id": 3, "name": "Main St"},
"area": {"id": 4, "name": "Kitchen"},
"assigned_employee": {"id": 42, "name": "Jordan Lee"},
"work_order_id": null,
"item_count": 4,
"done_count": 4,
"required_left": 0,
"flagged_count": 1,
"score": null,
"photo_count": 1,
"has_photo_proof": true,
"completed_at": "2026-10-16 08:41:10",
"completed_by": {"type": "employee", "id": 42, "name": "Jordan Lee"},
"missed_at": null,
"created_at": "2026-10-16 05:00:02",
"updated_at": "2026-10-16 08:41:10"
}
],
"meta": {"request_id": "req_xxx", "row_count": 1, "limit": 100, "has_more": false, "next_after_id": null, "filters": {"status": ["COMPLETED", "MISSED"], "from": "2026-10-01", "to": "2026-10-16"}}
}
/api/v1/operations/checklists/{checklist_run_id}Returns one checklist run with each item's answer (a tick, yes or no, a number such as a temperature, text or a score), its limits, corrective notes, and who answered it.
curl \
https://www.appyshift.com/acme/api/v1/operations/checklists/5531 \
--header "Authorization: Bearer aps_oauth_xxx"
{
"data": {
"id": 5531,
"name": "Cooler check",
"status": "COMPLETED",
"date": "2026-10-16",
"item_count": 2,
"done_count": 2,
"flagged_count": 1,
"completed_by": {"type": "employee", "id": 42, "name": "Jordan Lee"},
"items": [
{"id": 1, "label": "Walk-in cooler temperature", "type": "NUMBER", "required": true, "done": true, "value": 43.5, "unit": "°F", "min_value": 33, "max_value": 41, "out_of_range": true, "corrective_note": "Moved stock to reach-in, called for repair.", "has_photo": false, "completed_at": "2026-10-16 08:35:00", "completed_by": {"type": "employee", "id": 42, "name": "Jordan Lee"}},
{"id": 2, "label": "Door closes fully", "type": "YES_NO", "required": true, "done": true, "value": false, "unit": null, "min_value": null, "max_value": null, "out_of_range": false, "corrective_note": null, "has_photo": true, "completed_at": "2026-10-16 08:40:00", "completed_by": {"type": "employee", "id": 42, "name": "Jordan Lee"}}
]
},
"meta": {"request_id": "req_xxx"}
}
/api/v1/operations/incidentsReturns the incident log: category, severity, when it happened, the location and employee involved, the follow-up owner and due date, and how it was resolved.
curl --get \
https://www.appyshift.com/acme/api/v1/operations/incidents \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "from=2026-10-01" \
--data-urlencode "to=2026-10-16" \
--data-urlencode "severity=HIGH"
{
"data": [
{
"id": 88,
"title": "Guest slipped near the entrance",
"description": "Floor was wet after mopping; no sign was out.",
"category": "SAFETY",
"category_label": "Safety",
"severity": "HIGH",
"status": "RESOLVED",
"incident_date": "2026-10-14",
"occurred_at": "2026-10-14 18:20:00",
"location": {"id": 3, "name": "Main St"},
"employee": null,
"reported_by_employee": {"id": 42, "name": "Jordan Lee"},
"follow_up": {"owner": {"type": "user", "id": 7, "name": "Morgan Ellis"}, "due_date": "2026-10-15"},
"work_order_id": null,
"photo_count": 2,
"resolved_at": "2026-10-15 10:02:00",
"resolved_by": {"type": "user", "id": 7, "name": "Morgan Ellis"},
"resolution_note": "Wet floor signs added to the closing checklist.",
"reopened_at": null,
"created_at": "2026-10-14 18:25:31",
"updated_at": "2026-10-15 10:02:00"
}
],
"meta": {"request_id": "req_xxx", "row_count": 1, "limit": 100, "has_more": false, "next_after_id": null, "filters": {"severity": "HIGH", "from": "2026-10-01", "to": "2026-10-16"}, "descriptions_withheld": false}
}
/api/v1/operations/tip-declarationsReturns the cash tips each employee declared, per shift or per day, with whether a manager confirmed them for payroll.
curl --get \
https://www.appyshift.com/acme/api/v1/operations/tip-declarations \
--header "Authorization: Bearer aps_oauth_xxx" \
--data-urlencode "from=2026-10-01" \
--data-urlencode "to=2026-10-15" \
--data-urlencode "status=CONFIRMED"
{
"data": [
{
"id": 301,
"employee": {"id": 42, "name": "Jordan Lee"},
"work_date": "2026-10-14",
"time_entry_id": 99812,
"location": {"id": 3, "name": "Main St"},
"amount_cents": 4650,
"amount": 46.5,
"status": "CONFIRMED",
"source": "EMPLOYEE",
"declared_at": "2026-10-14 22:41:00",
"confirmed_at": "2026-10-15 09:10:00",
"voided_at": null,
"created_at": "2026-10-14 22:41:00",
"updated_at": "2026-10-15 09:10:00"
}
],
"meta": {"request_id": "req_xxx", "row_count": 1, "limit": 100, "has_more": false, "next_after_id": null, "filters": {"status": ["CONFIRMED"], "from": "2026-10-01", "to": "2026-10-15"}}
}
Subscribe an HTTPS endpoint to operational events such as schedule publication and time-off decisions. AppyShift sends an event envelope as JSON after the application change is committed.
Webhook registration is separate from OAuth API clients. A user with settings.integrations.manage can add the target URL, select event filters, attach a signing-secret credential, send a test event, and inspect or retry deliveries.
integration.testAn administrator queues a test event from Integrations Hub.
ViewIntegrationTestWebhookPayload
employee.createdA new employee profile is committed.
ViewEmployeeWebhookPayload
employee.updatedAn employee profile, status, termination, or reactivation is committed.
ViewEmployeeWebhookPayload
schedule.publishedA full or scoped weekly schedule publication changes the employee-visible schedule.
ViewSchedulePublishedWebhookPayload
pto.requestedAn employee, manager, or administrator submits a time-off request. The legacy pto name applies to every supported leave type.
ViewTimeOffRequestedWebhookPayload
pto.approvedA time-off request moves to approved from another status.
ViewTimeOffApprovedWebhookPayload
pto.deniedA time-off request moves to denied from another status.
ViewTimeOffDeniedWebhookPayload
pto.cancelledA manager or administrator moves a time-off request to cancelled.
ViewTimeOffCancelledWebhookPayload
time_entry.approvedA reviewed time entry moves to approved individually or in bulk.
ViewTimeEntryApprovedWebhookPayload
time_entry.rejectedA reviewed time entry moves to rejected individually or in bulk.
ViewTimeEntryRejectedWebhookPayload
shift_swap.approvedA shift swap or shift-board pickup is approved manually or automatically.
ViewShiftSwapApprovedWebhookPayload
shift_swap.rejectedA manager rejects a shift swap or shift-board pickup.
ViewShiftSwapRejectedWebhookPayload
payroll.exportedAn authorized user downloads the primary payroll export.
ViewPayrollExportedWebhookPayload
tip_pool.approvedA pending tip pool is approved individually or from the manager task inbox.
ViewTipPoolApprovedWebhookPayload
payroll.run.approvedA calculated payroll is approved (after the second approval when the company requires two).
ViewPayrollRunWebhookPayload
payroll.run.paidA payroll is marked paid, by a person or by automatic payment. Reversing payrolls made when a pay statement is voided do not send it.
ViewPayrollRunWebhookPayload
recognition.shout_out.createdA shout-out goes live on the company board: sent in the company app, the employee app or the API, or approved by a manager after waiting for approval.
ViewRecognitionShoutOutCreatedWebhookPayload
recruiting.applicant.createdSomeone applies on the careers page, or an API client adds an applicant.
ViewRecruitingApplicantCreatedWebhookPayload
recruiting.applicant.stage_changedAn applicant moves to another stage on the Applicants screen (one at a time or in bulk), through Hire & set up employee, or through the API.
ViewRecruitingApplicantStageWebhookPayload
recruiting.applicant.hiredAn applicant moves to Hired, usually with Hire & set up employee. Sent after recruiting.applicant.stage_changed.
ViewRecruitingApplicantStageWebhookPayload
announcement.publishedAn announcement is posted on the Announcements page or through POST /api/v1/announcements. A scheduled one is sent when it is posted, with status scheduled and its future published_at.
ViewAnnouncementPublishedWebhookPayload
onboarding.completedAn employee completes every currently available onboarding task.
ViewOnboardingCompletedWebhookPayload
onboarding.startedAn onboarding plan is assigned to an employee who had no onboarding tasks yet (from the employee's onboarding page, a new hire, or a hired applicant).
ViewOnboardingStartedWebhookPayload
training.assignedA course or quick quiz is assigned to an employee: by a person, an automatic rule, a learning path, a renewal, an onboarding task, or the employee starting an open course. Pro plan.
ViewTrainingWebhookPayload
training.completedAn employee passes a course or quick quiz in AppyShift, or staff record or import training taken elsewhere. Pro plan.
ViewTrainingWebhookPayload
training.certification_recordedPassing a course that counts as a certification records the employee's certification. Pro plan.
ViewTrainingWebhookPayload
operations.work_order.createdA work order is added: through the API, by a manager, from a customer site's repeat plan, or when a manager accepts an employee's request. Only while work orders are on.
ViewOperationsWorkOrderWebhookPayload
operations.work_order.completedA work order is marked done: by a manager on the Work orders page or the older Operations board, or by the assigned employee in My work (after any required photo or customer sign-off), or a manager adds a work order that is already done. Only while work orders are on.
ViewOperationsWorkOrderWebhookPayload
View the common WebhookEnvelope schema
| Header | Meaning |
|---|---|
Content-Type | application/json |
X-AppyShift-Event | Event name, matching the envelope's event property. |
X-AppyShift-Delivery | Stable delivery ID. Persist it as an idempotency key so a retry does not apply the event twice. |
X-AppyShift-Timestamp | Unix timestamp included when a signing credential is attached. |
X-AppyShift-Signature | sha256= followed by the lowercase HMAC-SHA256 signature. |
2xx status after safely accepting the event. Other responses are treated as delivery failures.Compute the HMAC over the exact timestamp header, a period, and the unmodified request body. Compare signatures with a constant-time function before parsing or processing the event.
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_APPYSHIFT_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_APPYSHIFT_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit('Stale webhook timestamp');
}
$expected = 'sha256=' . hash_hmac(
'sha256',
$timestamp . '.' . $rawBody,
$webhookSigningSecret
);
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit('Invalid signature');
}
{
"id": 9821,
"event": "schedule.published",
"portal_slug": "acme",
"aggregate_type": "schedule_week",
"aggregate_id": "2026-08-17",
"payload": {
"week_start": "2026-08-17",
"week_end": "2026-08-23",
"shift_count": 42,
"notified_employee_count": 18,
"change_summary": {
"new_shifts": 4,
"removed_shifts": 1,
"time_changes": 2,
"changed_employees": 6,
"affected_employee_ids": [14, 22, 31, 42, 56, 61]
},
"publication_scope": {"date": null, "department_id": null},
"publication_scope_label": "the full week",
"remaining_draft_count": 0,
"published_by": 7,
"published_at": "2026-08-19T14:42:10-05:00"
},
"created_at": "2026-08-19 14:42:10"
}
{
"id": 9822,
"event": "pto.requested",
"portal_slug": "acme",
"aggregate_type": "time_off_request",
"aggregate_id": "417",
"payload": {
"request": {
"id": 417,
"employee_id": 42,
"employee_name": "Jordan Lee",
"type": "PTO",
"start_date": "2026-09-03",
"end_date": "2026-09-05",
"status": "PENDING"
},
"actor": {
"type": "EMPLOYEE",
"id": 42,
"name": "Jordan Lee"
},
"requested_at": "2026-08-19T14:48:22-05:00"
},
"created_at": "2026-08-19 14:48:22"
}
{
"id": 9825,
"event": "pto.approved",
"portal_slug": "acme",
"aggregate_type": "time_off_request",
"aggregate_id": "417",
"payload": {
"request": {
"id": 417,
"employee_id": 42,
"employee_name": "Jordan Lee",
"type": "PTO",
"start_date": "2026-09-03",
"end_date": "2026-09-05",
"days_requested": 3,
"previous_status": "PENDING",
"status": "APPROVED"
},
"approved_by": 7,
"approved_at": "2026-08-20T09:05:11-05:00"
},
"created_at": "2026-08-20 09:05:11"
}
{
"id": 9826,
"event": "pto.denied",
"portal_slug": "acme",
"aggregate_type": "time_off_request",
"aggregate_id": "418",
"payload": {
"request": {
"id": 418,
"employee_id": 56,
"employee_name": "Taylor Morgan",
"type": "UNPAID",
"start_date": "2026-09-08",
"end_date": "2026-09-08",
"days_requested": 1,
"previous_status": "PENDING",
"status": "DENIED"
},
"denied_by": 7,
"denied_at": "2026-08-20T09:08:14-05:00"
},
"created_at": "2026-08-20 09:08:14"
}
{
"id": 9827,
"event": "pto.cancelled",
"portal_slug": "acme",
"aggregate_type": "time_off_request",
"aggregate_id": "417",
"payload": {
"request": {
"id": 417,
"employee_id": 42,
"employee_name": "Jordan Lee",
"type": "PTO",
"start_date": "2026-09-03",
"end_date": "2026-09-05",
"days_requested": 3,
"previous_status": "APPROVED",
"status": "CANCELLED"
},
"cancelled_by": 7,
"cancelled_at": "2026-08-20T09:12:03-05:00"
},
"created_at": "2026-08-20 09:12:03"
}
{
"id": 9828,
"event": "time_entry.approved",
"portal_slug": "acme",
"aggregate_type": "time_entry",
"aggregate_id": "8031",
"payload": {
"time_entry": {
"id": 8031,
"employee_id": 42,
"employee_name": "Jordan Lee",
"shift_id": 5512,
"entry_date": "2026-08-19",
"clock_in": "2026-08-19 08:00:00",
"clock_out": "2026-08-19 16:30:00",
"break_minutes": 30,
"net_minutes": 480,
"status": "APPROVED",
"entry_source": "MOBILE"
},
"previous_status": "PENDING",
"approved_by": 7,
"approved_at": "2026-08-20T09:15:40-05:00"
},
"created_at": "2026-08-20 09:15:40"
}
{
"id": 9829,
"event": "time_entry.rejected",
"portal_slug": "acme",
"aggregate_type": "time_entry",
"aggregate_id": "8032",
"payload": {
"time_entry": {
"id": 8032,
"employee_id": 56,
"employee_name": "Taylor Morgan",
"shift_id": 5518,
"entry_date": "2026-08-19",
"clock_in": "2026-08-19 12:00:00",
"clock_out": "2026-08-19 20:15:00",
"break_minutes": 30,
"net_minutes": 465,
"status": "REJECTED",
"entry_source": "EMPLOYEE"
},
"previous_status": "PENDING",
"rejected_by": 7,
"rejected_at": "2026-08-20T09:17:22-05:00"
},
"created_at": "2026-08-20 09:17:22"
}
{
"id": 9830,
"event": "shift_swap.approved",
"portal_slug": "acme",
"aggregate_type": "shift_swap",
"aggregate_id": "284",
"payload": {
"swap": {
"id": 284,
"request_type": "GIVE_AWAY",
"requester_id": 42,
"requester_name": "Jordan Lee",
"requester_shift_id": 5512,
"requester_shift_date": "2026-08-22",
"requester_shift_time": "08:00:00-16:00:00",
"target_id": 56,
"target_name": "Taylor Morgan",
"target_shift_id": null,
"target_shift_date": null,
"target_shift_time": null,
"status": "APPROVED"
},
"previous_status": "TARGET_ACCEPTED",
"approved_by": null,
"approved_at": "2026-08-20T09:20:00-05:00"
},
"created_at": "2026-08-20 09:20:00"
}
{
"id": 9831,
"event": "shift_swap.rejected",
"portal_slug": "acme",
"aggregate_type": "shift_swap",
"aggregate_id": "285",
"payload": {
"swap": {
"id": 285,
"request_type": "SWAP",
"requester_id": 42,
"requester_name": "Jordan Lee",
"requester_shift_id": 5512,
"requester_shift_date": "2026-08-22",
"requester_shift_time": "08:00:00-16:00:00",
"target_id": 56,
"target_name": "Taylor Morgan",
"target_shift_id": 5520,
"target_shift_date": "2026-08-23",
"target_shift_time": "12:00:00-20:00:00",
"status": "REJECTED"
},
"previous_status": "TARGET_ACCEPTED",
"rejected_by": 7,
"rejected_at": "2026-08-20T09:22:05-05:00"
},
"created_at": "2026-08-20 09:22:05"
}
{
"id": 9830,
"event": "onboarding.completed",
"portal_slug": "acme",
"aggregate_type": "employee_onboarding",
"aggregate_id": "42",
"payload": {
"employee": {
"id": 42,
"display_name": "Jordan Lee",
"manager_id": 9,
"hire_date": "2026-08-24"
},
"completion": {
"completed_task_id": 812,
"available_task_count": 7,
"completed_task_count": 7,
"completed_at": "2026-08-20T11:15:00-05:00"
},
"actor": {"type": "EMPLOYEE", "id": 42}
},
"created_at": "2026-08-20 11:15:00"
}
{
"id": 9902,
"event": "training.completed",
"portal_slug": "acme",
"aggregate_type": "training_assignment",
"aggregate_id": "318",
"payload": {
"employee": {"id": 42, "display_name": "Jordan Lee", "payroll_id": "E1042"},
"course": {"id": 27, "title": "Food safety basics", "version": 3},
"assignment": {
"id": 318,
"status": "PASSED",
"due_date": "2026-11-06",
"assigned_at": "2026-10-23 14:05:00",
"cycle": 1,
"passed_on": "2026-10-24",
"expires_on": null,
"completed_how": "in_app",
"started_by_employee": false
}
},
"created_at": "2026-10-24 15:20:00"
}
{
"id": 9834,
"event": "payroll.exported",
"portal_slug": "acme",
"aggregate_type": "payroll_export",
"aggregate_id": "generic_payroll_20260810_20260823.csv",
"payload": {
"export": {
"provider": "generic",
"company_code": "ACME01",
"date_from": "2026-08-10",
"date_to": "2026-08-23",
"filename": "generic_payroll_20260810_20260823.csv",
"format": "csv",
"row_count": 18,
"total_hours": 1284.5,
"regular_hours": 1200,
"overtime_hours": 84.5,
"double_overtime_hours": 0,
"missing_payroll_id_count": 0
},
"exported_by": {"id": 7, "name": "Morgan Ellis"},
"exported_at": "2026-08-20T14:05:00-05:00"
},
"created_at": "2026-08-20 14:05:00"
}
{
"id": 9838,
"event": "tip_pool.approved",
"portal_slug": "acme",
"aggregate_type": "tip_pool",
"aggregate_id": "284",
"payload": {
"tip_pool": {
"id": 284,
"pool_date": "2026-08-19",
"work_location_id": 3,
"location": "Main Office",
"shift_label": "Dinner",
"total_tips": 842.35,
"split_method": "HOURS_WORKED",
"payroll_earning_code": "TIPS",
"source_type": "POLICY",
"allocation_count": 12,
"status": "APPROVED"
},
"approved_by": 7,
"approved_at": "2026-08-20T15:20:00-05:00"
},
"created_at": "2026-08-20 15:20:00"
}
{
"id": 9901,
"event": "payroll.run.approved",
"portal_slug": "acme",
"aggregate_type": "payroll_run",
"aggregate_id": "318",
"payload": {
"run": {
"id": 318,
"run_code": "PAY-20260816-20260831-A1B2C3",
"label": "Aug 16 – 31, 2026",
"run_type": "REGULAR",
"status": "APPROVED",
"period_start": "2026-08-16",
"period_end": "2026-08-31",
"pay_date": "2026-09-04",
"employee_count": 18,
"gross_pay": 42810.55,
"employee_taxes": 6120.4,
"employer_taxes": 3488.12,
"deductions": 2210,
"net_pay": 34480.15,
"approved_at": "2026-09-02 15:41:09",
"paid_at": null,
"voided_at": null,
"correction": false,
"void_reversal": false,
"voided_statement_count": 0
}
},
"created_at": "2026-09-02 15:41:09"
}
{
"id": 9918,
"event": "payroll.run.paid",
"portal_slug": "acme",
"aggregate_type": "payroll_run",
"aggregate_id": "318",
"payload": {
"run": {
"id": 318,
"run_code": "PAY-20260816-20260831-A1B2C3",
"label": "Aug 16 – 31, 2026",
"run_type": "REGULAR",
"status": "PAID",
"period_start": "2026-08-16",
"period_end": "2026-08-31",
"pay_date": "2026-09-04",
"employee_count": 18,
"gross_pay": 42810.55,
"employee_taxes": 6120.4,
"employer_taxes": 3488.12,
"deductions": 2210,
"net_pay": 34480.15,
"approved_at": "2026-09-02 15:41:09",
"paid_at": "2026-09-04 09:02:44",
"voided_at": null,
"correction": false,
"void_reversal": false,
"voided_statement_count": 0
}
},
"created_at": "2026-09-04 09:02:44"
}
{
"id": 9021,
"event": "recognition.shout_out.created",
"portal_slug": "acme",
"aggregate_type": "culture_shout_out",
"aggregate_id": "5121",
"payload": {
"shout_out": {
"id": 5121,
"created_at": "2026-10-16 09:30:02",
"status": "PUBLISHED",
"visibility": "everyone",
"from": {"type": "employee", "employee_id": 42, "name": "Avery Stone"},
"to_employees": [{"id": 57, "name": "Jordan Lee"}],
"message": "Covered my Saturday close on short notice.",
"value": {"key": "COVERED_SHIFT", "label": "Covered a shift"},
"points_awarded": 20,
"points_pending": 0
},
"source": "api",
"occurred_at": "2026-10-16T09:30:02-05:00"
},
"created_at": "2026-10-16 09:30:02"
}
{
"id": 9901,
"event": "recruiting.applicant.created",
"portal_slug": "acme",
"aggregate_type": "recruiting_application",
"aggregate_id": "512",
"payload": {
"applicant": {
"id": 512,
"candidate_id": 301,
"job_id": 14,
"job_title": "Line Cook",
"first_name": "Riley",
"last_name": "Chen",
"email": "riley.chen@example.com",
"phone": "(555) 010-4420",
"stage": "APPLIED",
"stage_label": "Applied",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 15:02:11",
"updated_at": "2026-10-14 15:02:11"
},
"channel": "API",
"api_client": "Indeed connector"
},
"created_at": "2026-10-14 15:02:11"
}
{
"id": 9902,
"event": "recruiting.applicant.stage_changed",
"portal_slug": "acme",
"aggregate_type": "recruiting_application",
"aggregate_id": "512",
"payload": {
"applicant": {
"id": 512,
"candidate_id": 301,
"job_id": 14,
"job_title": "Line Cook",
"first_name": "Riley",
"last_name": "Chen",
"email": "riley.chen@example.com",
"phone": "(555) 010-4420",
"stage": "INTERVIEW",
"stage_label": "Interview",
"source": "Indeed",
"employee_id": null,
"applied_at": "2026-10-14 15:02:11",
"updated_at": "2026-10-16 10:15:00"
},
"previous_stage": "SCREENING",
"stage": "INTERVIEW",
"changed_at": "2026-10-16T10:15:00-05:00",
"changed_by": {"type": "USER", "name": "Pat Morgan"}
},
"created_at": "2026-10-16 10:15:00"
}
{
"id": 9903,
"event": "recruiting.applicant.hired",
"portal_slug": "acme",
"aggregate_type": "recruiting_application",
"aggregate_id": "512",
"payload": {
"applicant": {
"id": 512,
"candidate_id": 301,
"job_id": 14,
"job_title": "Line Cook",
"first_name": "Riley",
"last_name": "Chen",
"email": "riley.chen@example.com",
"phone": "(555) 010-4420",
"stage": "HIRED",
"stage_label": "Hired",
"source": "Indeed",
"employee_id": 88,
"applied_at": "2026-10-14 15:02:11",
"updated_at": "2026-10-16 10:15:00"
},
"previous_stage": "OFFER",
"stage": "HIRED",
"changed_at": "2026-10-16T10:15:00-05:00",
"changed_by": {"type": "USER", "name": "Pat Morgan"}
},
"created_at": "2026-10-16 10:15:00"
}
{
"id": 9910,
"event": "announcement.published",
"portal_slug": "acme",
"aggregate_type": "announcement",
"aggregate_id": "318",
"payload": {
"announcement": {
"id": 318,
"title": "Holiday hours",
"body": "The store closes at 3 PM on Friday.",
"priority": "HIGH",
"audience": {"type": "everyone"},
"status": "active",
"published_at": "2026-10-16 09:00:00",
"expires_at": null,
"author": {"user_id": 7, "name": "Pat Morgan"},
"requires_acknowledgement": false,
"created_at": "2026-10-15 16:42:10"
},
"actor": {"type": "USER", "id": 7, "name": "Pat Morgan"},
"posted_at": "2026-10-16T09:00:00-05:00"
},
"created_at": "2026-10-16 09:00:00"
}
{
"id": 9829,
"event": "onboarding.started",
"portal_slug": "acme",
"aggregate_type": "employee_onboarding",
"aggregate_id": "42",
"payload": {
"employee": {
"id": 42,
"display_name": "Jordan Lee",
"manager_id": 9,
"hire_date": "2026-08-24"
},
"onboarding": {
"plan_id": 3,
"plan_name": "Front desk onboarding",
"task_count": 7,
"started_at": "2026-08-18T09:12:00-05:00"
},
"actor": {"type": "USER", "id": 7}
},
"created_at": "2026-08-18 09:12:00"
}
{
"id": 9901,
"event": "operations.work_order.created",
"portal_slug": "acme",
"aggregate_type": "work_order",
"aggregate_id": "1042",
"payload": {
"work_order": {
"id": 1042,
"code": "WO-1042",
"title": "Fix the walk-in cooler door",
"status": "OPEN",
"priority": "HIGH",
"work_order_date": "2026-10-16",
"assigned_employee": {"id": 42, "name": "Jordan Lee"},
"created_at": "2026-10-16 07:12:44"
},
"actor": {"type": "api_client", "id": 5, "name": "Facilities CRM"}
},
"created_at": "2026-10-16 07:12:44"
}
{
"id": 9944,
"event": "operations.work_order.completed",
"portal_slug": "acme",
"aggregate_type": "work_order",
"aggregate_id": "1042",
"payload": {
"work_order": {
"id": 1042,
"code": "WO-1042",
"title": "Fix the walk-in cooler door",
"status": "COMPLETED",
"photo_count": 2,
"signoff_count": 1,
"completed_at": "2026-10-16 11:48:02"
},
"actor": {"type": "employee", "id": 42, "name": "Jordan Lee"}
},
"created_at": "2026-10-16 11:48:02"
}
Use these field-by-field contracts alongside the endpoint examples. Dynamic report and custom-field values inherit the sensitivity classification advertised by their field definition.
No schemas match that search.
Form fields accepted by the client-credentials token endpoint. Client authentication is sent separately with HTTP Basic authentication.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
grant_type |
string |
Required | No | Standard | Must be client_credentials. | client_credentials |
scope |
string |
Optional | No | Standard | Space-delimited subset of scopes granted to the client. Omit to request every granted scope. | employees:read reports:run |
Short-lived bearer credential returned after successful client authentication.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
access_token |
string |
Required | No | Credential | Bearer token. Store as a secret and never expose it to browser code. | aps_oauth_xxx |
token_type |
string |
Required | No | Standard | Authorization scheme used with the token. | Bearer |
expires_in |
integer |
Required | No | Standard | Token lifetime in seconds. | 3600 |
scope |
string |
Required | No | Standard | Space-delimited scopes carried by the token. | employees:read reports:run |
Identity and operation discovery for the bearer token used on the request.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.api_version |
string |
Required | No | Standard | Protected API version described by the response. | v1 |
data.company_slug |
string |
Required | No | Standard | Company tenant bound to the token. | acme |
data.client.name |
string |
Required | No | Standard | Administrator-assigned integration name. | Payroll warehouse |
data.client.authentication |
enum |
Required | No | Standard | oauth2 or legacy_bearer. | oauth2 |
data.client.scopes |
array<string> |
Required | No | Standard | Exact scopes carried by this access token. | ["employees:read"] |
data.client.token_expires_at |
date-time |
Required | Yes | Standard | OAuth access-token expiry; null for a legacy bearer key. | 2026-08-20 16:30:00 |
data.client.client_expires_at |
date-time |
Required | Yes | Standard | Optional administrator-configured client expiry. | null |
data.operations |
array<ApiOperation> |
Required | No | Standard | Only operations whose required scopes are present on this token. | [{...}] |
data.operations[].method |
string |
Required | No | Standard | HTTP method. | GET |
data.operations[].path |
string |
Required | No | Standard | Versioned path appended to the company base URL. | /api/v1/employees |
data.operations[].required_scopes |
array<string> |
Required | No | Standard | Scopes required together for this operation. | ["employees:read"] |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.operation_count |
integer |
Required | No | Standard | Number of callable operations returned. | 3 |
Payload queued from Integrations Hub to verify endpoint configuration and delivery.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
source |
string |
Required | No | Standard | AppyShift surface that queued the test. | settings.integrations |
queued_by |
integer |
Required | Yes | Standard | User ID that queued the test. | 7 |
queued_at |
date-time |
Required | No | Standard | ISO 8601 queue timestamp. | 2026-08-19T14:42:10-05:00 |
Optional filters for employee certifications and licenses.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee_id |
integer |
Optional | No | Standard | Return credentials for one employee. | 42 |
status |
string |
Optional | No | Standard | Exact credential status, normalized to uppercase. | ACTIVE |
expiring_within_days |
integer |
Optional | No | Standard | Return unexpired credentials expiring within this many days. | 60 |
Employee certification and license records.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<Credential> |
Required | No | Conditional | Matching credentials. | [{...}] |
data[].id |
integer |
Required | No | Standard | Credential record ID. | 91 |
data[].employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data[].certification_name |
string |
Required | No | Standard | Certification or license name. | Food Handler |
data[].credential_number |
string |
Required | No | Conditional | Credential number, or an empty string. | FH-10293 |
data[].issued_at |
date |
Required | Yes | Standard | Issue date. | 2026-01-10 |
data[].expires_at |
date |
Required | Yes | Standard | Expiry date. | 2027-01-10 |
data[].status |
string |
Required | No | Standard | Credential workflow status. | ACTIVE |
data[].verified_at |
date-time |
Required | Yes | Standard | Verification timestamp. | 2026-01-11 10:00:00 |
meta.row_count |
integer |
Required | No | Standard | Credentials returned. | 1 |
Company departments and current active employee counts.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Department ID. | 7 |
data[].name |
string |
Required | No | Standard | Department name. | Front Desk |
data[].description |
string |
Required | No | Standard | Description, or an empty string. | Guest arrival team |
data[].color |
string |
Required | No | Standard | Configured display color. | #2563eb |
data[].employee_count |
integer |
Required | No | Standard | Active employees in the department. | 12 |
Company job positions and current active employee counts.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Position ID. | 12 |
data[].title |
string |
Required | No | Standard | Position title. | Guest Services Lead |
data[].description |
string |
Required | No | Standard | Description, or an empty string. | Leads guest arrival operations |
data[].department_name |
string |
Required | No | Standard | Related department, or an empty string. | Front Desk |
data[].employee_count |
integer |
Required | No | Standard | Active employees in the position. | 3 |
Company work locations, addresses, and time-clock geofence settings.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Location ID. | 3 |
data[].name |
string |
Required | No | Standard | Location name. | Main Office |
data[].address |
string |
Required | No | Conditional | Street address, or an empty string. | 100 Main St |
data[].city |
string |
Required | No | Conditional | City, or an empty string. | Austin |
data[].state |
string |
Required | No | Conditional | State or region, or an empty string. | TX |
data[].zip |
string |
Required | No | Conditional | Postal code, or an empty string. | 78701 |
data[].lat |
number |
Required | Yes | Conditional | Latitude. | 30.2672 |
data[].lon |
number |
Required | Yes | Conditional | Longitude. | -97.7431 |
data[].is_active |
boolean |
Required | No | Standard | Whether the work location is active. | true |
data[].geofence_radius_feet |
integer |
Required | Yes | Conditional | Allowed clock radius in feet. | 500 |
data[].employee_count |
integer |
Required | No | Standard | Active employees assigned to the location. | 18 |
Optional query parameters for filtering and cursor-paginating the employee roster.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
status |
enum |
Optional | No | Standard | ACTIVE, INACTIVE, ON_LEAVE, or TERMINATED. | ACTIVE |
department_id |
integer |
Optional | No | Standard | Positive department ID. | 7 |
updated_since |
date-time |
Optional | No | Standard | ISO 8601 date or timestamp, inclusive. | 2026-08-01T00:00:00Z |
limit |
integer |
Optional | No | Standard | Enables cursor pagination. Range 1-500; defaults to 100 when pagination is requested. | 100 |
after_id |
integer |
Optional | No | Standard | Return employees with IDs greater than this cursor. | 42 |
A standard employee roster page. Sensitive profile and custom values are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<EmployeeSummary> |
Required | No | Standard | Employees visible within the company tenant. | [{...}] |
data[].id |
integer |
Required | No | Standard | Employee ID used by detail and field-value endpoints. | 42 |
data[].name |
string |
Required | No | Standard | Legal first and last name joined for display. | Jordan Lee |
data[].email |
string |
Required | No | Standard | Work email stored on the employee profile. | jordan.lee@example.com |
data[].payroll_id |
string |
Required | No | Standard | External payroll identifier; an empty string means none is assigned. | EE-1042 |
data[].department_id |
integer |
Required | Yes | Standard | Department relationship ID. | 7 |
data[].department |
string |
Required | No | Standard | Department display name, or an empty string. | Front Desk |
data[].position_id |
integer |
Required | Yes | Standard | Position relationship ID. | 12 |
data[].job_title |
string |
Required | No | Standard | Position title, or an empty string. | Guest Services Lead |
data[].pay_type |
string |
Required | No | Standard | Employee pay type without compensation values. | HOURLY |
data[].status |
enum |
Required | No | Standard | Current employee status. | ACTIVE |
data[].active |
boolean |
Required | No | Standard | True only when status is ACTIVE. | true |
data[].updated_at |
date-time |
Required | No | Standard | Application database timestamp. | 2026-08-18 14:22:09 |
meta.request_id |
string |
Required | No | Standard | Request correlation ID used in access logs. | req_xxx |
meta.row_count |
integer |
Required | No | Standard | Employees returned in this response. | 1 |
meta.pagination.applied |
boolean |
Required | No | Standard | Whether limit or after_id enabled cursor pagination. | true |
meta.pagination.limit |
integer |
Required | Yes | Standard | Applied page size, or null for the backward-compatible unpaginated response. | 100 |
meta.pagination.has_more |
boolean |
Required | No | Standard | Whether another cursor page exists. | false |
meta.pagination.next_after_id |
integer |
Required | Yes | Standard | Pass this value as after_id for the next page. | 42 |
One employee’s standard non-sensitive profile and organization relationships.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Employee ID. | 42 |
data.first_name |
string |
Required | No | Standard | Legal first name. | Jordan |
data.last_name |
string |
Required | No | Standard | Legal last name. | Lee |
data.preferred_name |
string |
Required | No | Standard | Preferred name, or an empty string. | Jordy |
data.name |
string |
Required | No | Standard | Legal first and last name joined for display. | Jordan Lee |
data.email |
string |
Required | No | Standard | Work email. | jordan.lee@example.com |
data.phone |
string |
Required | No | Standard | Primary phone, or an empty string. | 555-123-4567 |
data.status |
enum |
Required | No | Standard | Current employee status. | ACTIVE |
data.employment_type |
string |
Required | No | Standard | Employment classification. | FULL_TIME |
data.department_id |
integer |
Required | Yes | Standard | Department relationship ID. | 7 |
data.department |
string |
Required | No | Standard | Department display name. | Front Desk |
data.position_id |
integer |
Required | Yes | Standard | Position relationship ID. | 12 |
data.position |
string |
Required | No | Standard | Position title. | Guest Services Lead |
data.manager_id |
integer |
Required | Yes | Standard | Manager employee ID. | 9 |
data.manager |
string |
Required | No | Standard | Manager display name, or an empty string. | Morgan Ellis |
data.hire_date |
date |
Required | No | Standard | ISO date, or an empty string. | 2026-05-01 |
data.termination_date |
date |
Required | No | Standard | ISO date, or an empty string. | "" |
data.location |
string |
Required | No | Standard | Legacy work-location label, or an empty string. | Main Office |
data.payroll_id |
string |
Required | No | Standard | External payroll identifier, or an empty string. | EE-1042 |
data.portal_enabled |
boolean |
Required | No | Standard | Whether employee self-service access is enabled. | true |
data.created_at |
date-time |
Required | No | Standard | Profile creation timestamp. | 2026-04-20 09:13:00 |
data.updated_at |
date-time |
Required | No | Standard | Last profile update timestamp. | 2026-08-18 14:22:09 |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
Query parameters for selecting reportable fields and their display formats for one employee.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
fields |
string |
Optional | No | Standard | Comma-separated field keys. Omit to return every field available to the token; maximum 500. | employee_name,hire_date,custom_17 |
formats[field_key] |
string |
Optional | No | Standard | Requested format key for a selected field. The response uses the catalog’s advertised output_field. | formats[hire_date]=us |
include_sensitive |
boolean |
Optional | No | Sensitive | Set to 1 only with reports.sensitive:read to expose sensitive fields. | 0 |
Formatted reportable values for one employee. Keys inside values depend on selected fields and formats.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data.values |
object<string, scalar|null> |
Required | No | Conditional | Dynamic map keyed by each selected format’s output_field. Classification inherits from its field definition. | {"hire_date_us":"05/01/2026"} |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.field_count |
integer |
Required | No | Standard | Number of output values returned. | 3 |
meta.fields |
array<FieldSelection> |
Required | No | Standard | Mapping from requested field keys to output keys. | [{...}] |
meta.fields[].field |
string |
Required | No | Standard | Requested catalog field key. | hire_date |
meta.fields[].output_field |
string |
Required | No | Standard | Key used in data.values after formatting. | hire_date_us |
meta.fields[].label |
string |
Required | No | Standard | Human-readable field label. | Hire Date |
meta.fields[].format |
string |
Required | No | Standard | Applied format key. | us |
meta.fields[].sensitive |
boolean |
Required | No | Standard | Whether the corresponding value is sensitive HR data. | false |
meta.sensitive_fields_included |
boolean |
Required | No | Standard | Whether include_sensitive was authorized and applied. | false |
Partial update body for active, reportable custom employee fields. Omitted fields remain unchanged.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
values |
object<string, scalar|null> |
Required | No | Conditional | Non-empty map containing at most 100 custom_N keys. Classification inherits from each field definition. | {"custom_17":"Extra Large"} |
values.custom_N |
string|number|boolean|null |
Required | Yes | Conditional | Value validated against the custom field type, required flag, and configured options. | Extra Large |
Normalized values returned after a successful partial custom-field update.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data.values |
object<string, string> |
Required | No | Conditional | Only submitted custom_N fields, normalized to stored strings. | {"custom_31":"1"} |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.changed_fields |
array<string> |
Required | No | Standard | Submitted keys whose stored value actually changed. | ["custom_17"] |
Optional query parameter controlling whether sensitive field definitions are visible.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
include_sensitive |
boolean |
Optional | No | Sensitive | Set to 1 only with reports.sensitive:read. | 0 |
Field definitions used to build selectors, validate custom-field writes, and request consistent output formats.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<EmployeeFieldDefinition> |
Required | No | Standard | Reportable fields visible to this token. | [{...}] |
data[].key |
string |
Required | No | Standard | Stable request key such as employee_name or custom_17. | employee_name |
data[].label |
string |
Required | No | Standard | Human-readable label. | Employee |
data[].group |
string |
Required | No | Standard | UI grouping label. | Identity |
data[].source |
enum |
Required | No | Standard | system or custom. | system |
data[].type |
string |
Required | No | Standard | system for built-ins; configured field type for custom fields. | system |
data[].custom_field_id |
integer |
Required | Yes | Standard | Numeric ID for custom fields; null for system fields. | 17 |
data[].writable |
boolean |
Required | No | Standard | Whether the field may be updated by the custom-field PATCH endpoint. | true |
data[].required |
boolean |
Required | No | Standard | Whether a custom field rejects an empty value. | false |
data[].options |
array<string> |
Required | No | Standard | Configured values for choice fields; otherwise empty. | ["Small","Large"] |
data[].available_on_roster |
boolean |
Required | No | Standard | Whether the field can appear as an employee roster column. | true |
data[].sensitive |
boolean |
Required | No | Standard | Whether values require sensitive-data authority. | false |
data[].formats |
array<FieldFormat> |
Required | No | Standard | Supported display formats; may be empty. | [{...}] |
data[].formats[].key |
string |
Required | No | Standard | Format key sent in formats[field_key]. | last_first |
data[].formats[].label |
string |
Required | No | Standard | Format display label. | Last, First |
data[].formats[].output_field |
string |
Required | No | Standard | Response property produced by this format. | employee_last_first |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.row_count |
integer |
Required | No | Standard | Field definitions returned. | 48 |
meta.sensitive_fields_included |
boolean |
Required | No | Standard | Whether sensitive definitions were authorized and included. | false |
Payload for employee.created and employee.updated. It includes operational profile data and selected compensation/contact fields, but excludes SSN, birth date, home address, notes, documents, and profile-photo filenames.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee |
object |
Required | No | Conditional | Employee state after the committed change. | {...} |
employee.id |
integer |
Required | No | Standard | Employee ID. | 42 |
employee.display_name |
string |
Required | No | Standard | Resolved display name. | Jordan Lee |
employee.first_name |
string |
Required | No | Standard | Legal first name. | Jordan |
employee.last_name |
string |
Required | No | Standard | Legal last name. | Lee |
employee.preferred_name |
string |
Required | Yes | Standard | Preferred name when one is stored. | Jordy |
employee.email |
string |
Required | No | Standard | Employee email address. | jordan.lee@example.com |
employee.phone |
string |
Required | Yes | Sensitive | Primary phone value. | 555-123-4567 |
employee.cell_phone |
string |
Required | Yes | Sensitive | Personal mobile phone value. | 555-123-4567 |
employee.home_phone |
string |
Required | Yes | Sensitive | Home phone value. | 555-987-6543 |
employee.status |
enum |
Required | No | Standard | Current employment status. | ACTIVE |
employee.employment_type |
string |
Required | Yes | Standard | Employment classification. | FULL_TIME |
employee.department_id |
integer |
Required | Yes | Standard | Department relationship ID. | 7 |
employee.department_name |
string |
Required | Yes | Standard | Department name. | Front Desk |
employee.position_id |
integer |
Required | Yes | Standard | Position relationship ID. | 12 |
employee.position_title |
string |
Required | Yes | Standard | Position title. | Guest Services Lead |
employee.manager_id |
integer |
Required | Yes | Standard | Manager employee ID. | 9 |
employee.manager_name |
string |
Required | Yes | Standard | Manager display name. | Morgan Ellis |
employee.hire_date |
date |
Required | No | Standard | Original hire date. | 2026-05-01 |
employee.rehire_date |
date |
Required | Yes | Standard | Most recent rehire date. | 2026-05-01 |
employee.termination_date |
date |
Required | Yes | Standard | Termination date when applicable. | 2026-12-31 |
employee.termination_reason |
string |
Required | Yes | Sensitive | Stored termination reason. | Voluntary |
employee.is_rehirable |
boolean |
Required | Yes | Sensitive | Rehire eligibility when recorded. | true |
employee.location |
string |
Required | Yes | Standard | Legacy work-location label. | Main Office |
employee.work_location_id |
integer |
Required | Yes | Standard | Work-location relationship ID. | 3 |
employee.pay_type |
string |
Required | Yes | Standard | Hourly or salary pay classification. | HOURLY |
employee.pay_rate |
number |
Required | Yes | Sensitive | Stored pay rate. Webhook administration should be restricted to trusted company administrators. | 24.50 |
employee.payroll_id |
string |
Required | Yes | Sensitive | External payroll identifier. | EE-1042 |
employee.time_clock_badge_id |
string |
Required | Yes | Sensitive | External clock/badge identifier. | 1042 |
employee.pto_policy_id |
integer |
Required | Yes | Standard | Assigned time-off policy ID. | 5 |
employee.portal_enabled |
boolean |
Required | No | Standard | Whether employee self-service access is enabled. | true |
employee.created_at |
date-time |
Required | No | Standard | Profile creation timestamp. | 2026-04-20 09:13:00 |
employee.updated_at |
date-time |
Required | No | Standard | Latest profile update timestamp. | 2026-08-19 14:42:10 |
previous_employee |
object |
Optional | No | Conditional | Previous employee state on employee.updated. Omitted on employee.created. | {...} |
changed_fields |
array<string> |
Required | No | Conditional | Properties that changed. Empty for employee.created. | ["department_id","department_name"] |
context |
object |
Required | No | Standard | Lifecycle source, timestamp, and operation-specific context. | {"source":"employees","occurred_at":"2026-08-19T14:42:10-05:00"} |
actor |
object |
Optional | No | Standard | Authenticated user that caused the change, when available. | {"id":7,"name":"Morgan Ellis","email":"morgan@example.com"} |
Required inclusive date range shared by time-entry and schedule feeds.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
start_date |
date |
Required | No | Standard | First included date in YYYY-MM-DD format. | 2026-08-01 |
end_date |
date |
Required | No | Standard | Last included date; no more than 62 days after start_date. | 2026-08-14 |
Completed time entries within the requested date range.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<TimeEntry> |
Required | No | Conditional | Completed clock entries in chronological order. | [{...}] |
data[].id |
integer |
Required | No | Standard | Time-entry ID. | 8221 |
data[].employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data[].employee_name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
data[].employee_payroll_id |
string |
Required | No | Conditional | External payroll identifier, or an empty string. | EE-1042 |
data[].work_date |
date |
Required | No | Standard | Work date assigned to the entry. | 2026-08-03 |
data[].clock_in |
date-time |
Required | No | Standard | Clock-in local database timestamp. | 2026-08-03 08:02:00 |
data[].clock_out |
date-time |
Required | No | Standard | Clock-out timestamp, advanced to the next day for overnight entries. | 2026-08-03 16:31:00 |
data[].hours |
number |
Required | No | Standard | Worked hours after breaks, rounded to four decimal places. | 8.0167 |
data[].entry_type |
string |
Required | No | Standard | Recorded entry source, defaulting to MANUAL on older schemas. | MOBILE |
data[].notes |
string |
Required | No | Conditional | Manager or employee notes, or an empty string. | "" |
meta.start_date |
date |
Required | No | Standard | Applied range start. | 2026-08-01 |
meta.end_date |
date |
Required | No | Standard | Applied range end. | 2026-08-14 |
meta.row_count |
integer |
Required | No | Standard | Entries returned. | 1 |
Scheduled shift assignments within the requested date range.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<ScheduleShift> |
Required | No | Standard | Shifts ordered by date and start time. | [{...}] |
data[].id |
integer |
Required | No | Standard | Shift ID. | 5512 |
data[].employee_id |
integer |
Required | No | Standard | Assigned employee ID. | 42 |
data[].employee_name |
string |
Required | No | Standard | Assigned employee name. | Jordan Lee |
data[].employee_payroll_id |
string |
Required | No | Conditional | External payroll identifier, or an empty string. | EE-1042 |
data[].shift_date |
date |
Required | No | Standard | Scheduled work date. | 2026-08-18 |
data[].start_time |
time |
Required | No | Standard | Local shift start time. | 08:00:00 |
data[].end_time |
time |
Required | No | Standard | Local shift end time. | 16:00:00 |
data[].status |
string |
Required | No | Standard | Shift publication or workflow status. | PUBLISHED |
data[].location |
string |
Required | No | Standard | Shift location label, or an empty string. | Main Office |
data[].notes |
string |
Required | No | Conditional | Shift notes, or an empty string. | "" |
data[].position_title |
string |
Required | No | Standard | Shift position title, or an empty string. | Guest Services Lead |
data[].department_name |
string |
Required | No | Standard | Assigned employee department, or an empty string. | Front Desk |
meta.row_count |
integer |
Required | No | Standard | Shifts returned. | 1 |
Selects either request history or annual leave balances.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
view |
enum |
Optional | No | Standard | requests (default) or balances. | requests |
start_date |
date |
Optional | No | Standard | Request-overlap range start; defaults to 90 days ago. | 2026-08-01 |
end_date |
date |
Optional | No | Standard | Request-overlap range end; defaults to today. | 2026-09-30 |
employee_id |
integer |
Optional | No | Standard | Optional employee filter for the requests view. | 42 |
year |
integer |
Optional | No | Standard | Four-digit year for the balances view; defaults to the current year. | 2026 |
Time-off request rows or leave-balance rows selected by the view query.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<TimeOffRequest|LeaveBalance> |
Required | No | Conditional | Rows for the selected view. | [{...}] |
data[].employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data[].employee_name |
string |
Required | No | Standard | Employee name. | Jordan Lee |
data[].employee_payroll_id |
string |
Required | No | Conditional | External payroll identifier, or an empty string. | EE-1042 |
data[].id |
integer |
Optional | No | Standard | Request ID; requests view only. | 381 |
data[].type |
string |
Optional | No | Standard | Request leave type; requests view only. | VACATION |
data[].start_date |
date |
Optional | No | Standard | Request start; requests view only. | 2026-09-08 |
data[].end_date |
date |
Optional | No | Standard | Request end; requests view only. | 2026-09-10 |
data[].status |
string |
Optional | No | Standard | Request workflow status. | APPROVED |
data[].reason |
string |
Optional | No | Conditional | Employee-provided reason. | Family trip |
data[].year |
integer |
Optional | No | Standard | Balance year; balances view only. | 2026 |
data[].leave_type |
string |
Optional | No | Standard | Balance leave type. | VACATION |
data[].allotted_hours |
number |
Optional | No | Conditional | Hours allotted for the year. | 80 |
data[].used_hours |
number |
Optional | No | Conditional | Hours used for the year. | 24 |
data[].remaining_hours |
number |
Optional | No | Conditional | Allotted minus used hours. | 56 |
meta.view |
enum |
Required | No | Standard | requests or balances. | requests |
meta.row_count |
integer |
Required | No | Standard | Rows returned. | 1 |
Payload produced when a full or scoped weekly schedule publication changes the employee-visible schedule.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
week_start |
date |
Required | No | Standard | First date in the published week. | 2026-08-17 |
week_end |
date |
Required | No | Standard | Last date in the published week. | 2026-08-23 |
shift_count |
integer |
Required | No | Standard | Published shifts in the selected scope. | 42 |
notified_employee_count |
integer |
Required | No | Standard | Employees selected for schedule-change notification. | 18 |
change_summary |
object |
Required | No | Standard | Counts and employee IDs describing the published difference. | {"new_shifts":4,"removed_shifts":1,"time_changes":2,"changed_employees":6,"affected_employee_ids":[14,22,31]} |
publication_scope |
object |
Required | No | Standard | Optional date and department filters used for scoped publication. | {"date":null,"department_id":null} |
publication_scope_label |
string |
Required | No | Standard | Human-readable publication scope. | the full week |
remaining_draft_count |
integer |
Required | No | Standard | Draft changes still outside the selected scope. | 0 |
published_by |
integer |
Required | Yes | Standard | User ID that published the schedule. | 7 |
published_at |
date-time |
Required | No | Standard | ISO 8601 publication timestamp. | 2026-08-19T14:42:10-05:00 |
Payload produced when an employee, manager, or administrator submits a time-off request. The pto.requested event name is retained for compatibility and applies to every leave type.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
request.id |
integer |
Required | No | Standard | Time-off request ID. | 417 |
request.employee_id |
integer |
Required | No | Standard | Requesting employee ID. | 42 |
request.employee_name |
string |
Required | Yes | Standard | Requesting employee display name when available. | Jordan Lee |
request.type |
string |
Required | No | Standard | Requested leave type. | PTO |
request.start_date |
date |
Required | No | Standard | First requested date. | 2026-09-03 |
request.end_date |
date |
Required | No | Standard | Last requested date. | 2026-09-05 |
request.status |
enum |
Required | No | Standard | Initial request status. | PENDING |
actor |
object |
Required | Yes | Standard | Employee or authenticated user that submitted the request. | {"type":"EMPLOYEE","id":42,"name":"Jordan Lee"} |
requested_at |
date-time |
Required | No | Standard | ISO 8601 submission timestamp. | 2026-08-19T14:48:22-05:00 |
Payload produced when a time-off request moves to approved. Free-text reasons and reviewer notes are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
request.id |
integer |
Required | No | Standard | Time-off request ID. | 417 |
request.employee_id |
integer |
Required | No | Standard | Approved employee ID. | 42 |
request.employee_name |
string |
Required | Yes | Standard | Approved employee display name when available. | Jordan Lee |
request.type |
string |
Required | No | Standard | Approved leave type. | PTO |
request.start_date |
date |
Required | No | Standard | First approved date. | 2026-09-03 |
request.end_date |
date |
Required | No | Standard | Last approved date. | 2026-09-05 |
request.days_requested |
integer |
Required | No | Standard | Inclusive calendar-day count. | 3 |
request.previous_status |
enum |
Required | No | Standard | Status before approval. | PENDING |
request.status |
enum |
Required | No | Standard | New request status. | APPROVED |
approved_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
approved_at |
date-time |
Required | No | Standard | ISO 8601 approval timestamp. | 2026-08-20T09:05:11-05:00 |
Payload produced when a time-off request moves to denied. Free-text reasons and reviewer notes are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
request.id |
integer |
Required | No | Standard | Time-off request ID. | 418 |
request.employee_id |
integer |
Required | No | Standard | Requesting employee ID. | 56 |
request.employee_name |
string |
Required | Yes | Standard | Employee display name when available. | Taylor Morgan |
request.type |
string |
Required | No | Standard | Requested leave type. | UNPAID |
request.start_date |
date |
Required | No | Standard | First requested date. | 2026-09-08 |
request.end_date |
date |
Required | No | Standard | Last requested date. | 2026-09-08 |
request.days_requested |
integer |
Required | No | Standard | Inclusive calendar-day count. | 1 |
request.previous_status |
enum |
Required | No | Standard | Status before denial. | PENDING |
request.status |
enum |
Required | No | Standard | New request status. | DENIED |
denied_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
denied_at |
date-time |
Required | No | Standard | ISO 8601 denial timestamp. | 2026-08-20T09:08:14-05:00 |
Payload produced when a manager or administrator moves a time-off request to cancelled. Free-text reasons and reviewer notes are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
request.id |
integer |
Required | No | Standard | Time-off request ID. | 417 |
request.employee_id |
integer |
Required | No | Standard | Requesting employee ID. | 42 |
request.employee_name |
string |
Required | Yes | Standard | Employee display name when available. | Jordan Lee |
request.type |
string |
Required | No | Standard | Requested leave type. | PTO |
request.start_date |
date |
Required | No | Standard | First requested date. | 2026-09-03 |
request.end_date |
date |
Required | No | Standard | Last requested date. | 2026-09-05 |
request.days_requested |
integer |
Required | No | Standard | Inclusive calendar-day count. | 3 |
request.previous_status |
enum |
Required | No | Standard | Status before cancellation. | APPROVED |
request.status |
enum |
Required | No | Standard | New request status. | CANCELLED |
cancelled_by |
integer |
Required | Yes | Standard | User ID that cancelled the request. | 7 |
cancelled_at |
date-time |
Required | No | Standard | ISO 8601 cancellation timestamp. | 2026-08-20T09:12:03-05:00 |
Payload produced after a reviewed time entry is approved.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
time_entry.id |
integer |
Required | No | Standard | Time-entry ID. | 8031 |
time_entry.employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
time_entry.employee_name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
time_entry.shift_id |
integer |
Required | Yes | Standard | Associated scheduled-shift ID. | 5512 |
time_entry.entry_date |
date |
Required | No | Standard | Work date. | 2026-08-19 |
time_entry.clock_in |
date-time |
Required | No | Standard | Recorded clock-in value. | 2026-08-19 08:00:00 |
time_entry.clock_out |
date-time |
Required | No | Standard | Recorded clock-out value. | 2026-08-19 16:30:00 |
time_entry.break_minutes |
integer |
Required | No | Standard | Unpaid break minutes. | 30 |
time_entry.net_minutes |
integer |
Required | No | Standard | Net approved work minutes. | 480 |
time_entry.status |
enum |
Required | No | Standard | New entry status. | APPROVED |
time_entry.entry_source |
string |
Required | No | Standard | Origin of the time entry. | MOBILE |
previous_status |
enum |
Required | No | Standard | Status before approval. | PENDING |
approved_by |
integer |
Required | No | Standard | Reviewing user ID. | 7 |
approved_at |
date-time |
Required | No | Standard | ISO 8601 approval timestamp. | 2026-08-20T09:05:11-05:00 |
Payload produced after a reviewed time entry is rejected. Free-text review notes are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
time_entry.id |
integer |
Required | No | Standard | Time-entry ID. | 8032 |
time_entry.employee_id |
integer |
Required | No | Standard | Employee ID. | 56 |
time_entry.employee_name |
string |
Required | No | Standard | Employee display name. | Taylor Morgan |
time_entry.shift_id |
integer |
Required | Yes | Standard | Associated scheduled-shift ID. | 5518 |
time_entry.entry_date |
date |
Required | No | Standard | Work date. | 2026-08-19 |
time_entry.clock_in |
date-time |
Required | No | Standard | Recorded clock-in value. | 2026-08-19 12:00:00 |
time_entry.clock_out |
date-time |
Required | No | Standard | Recorded clock-out value. | 2026-08-19 20:15:00 |
time_entry.break_minutes |
integer |
Required | No | Standard | Unpaid break minutes. | 30 |
time_entry.net_minutes |
integer |
Required | No | Standard | Net recorded work minutes. | 465 |
time_entry.status |
enum |
Required | No | Standard | New entry status. | REJECTED |
time_entry.entry_source |
string |
Required | No | Standard | Origin of the time entry. | EMPLOYEE |
previous_status |
enum |
Required | No | Standard | Status before rejection. | PENDING |
rejected_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
rejected_at |
date-time |
Required | No | Standard | ISO 8601 rejection timestamp. | 2026-08-20T09:17:22-05:00 |
Payload produced after a shift swap or shift-board pickup is approved.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
swap.id |
integer |
Required | No | Standard | Coverage-request ID. | 284 |
swap.request_type |
enum |
Required | No | Standard | Swap or give-away request type. | SWAP |
swap.requester_id |
integer |
Required | No | Standard | Requesting employee ID. | 42 |
swap.requester_name |
string |
Required | No | Standard | Requesting employee display name. | Jordan Lee |
swap.requester_shift_id |
integer |
Required | No | Standard | Requester shift ID. | 5512 |
swap.requester_shift_date |
date |
Required | No | Standard | Requester shift date. | 2026-08-22 |
swap.requester_shift_time |
string |
Required | No | Standard | Requester shift time range. | 08:00 - 16:00 |
swap.target_id |
integer |
Required | Yes | Standard | Receiving employee ID. | 56 |
swap.target_name |
string |
Required | Yes | Standard | Receiving employee display name. | Taylor Morgan |
swap.target_shift_id |
integer |
Required | Yes | Standard | Target shift ID for an exchange. | 5520 |
swap.target_shift_date |
date |
Required | Yes | Standard | Target shift date for an exchange. | 2026-08-23 |
swap.target_shift_time |
string |
Required | Yes | Standard | Target shift time range for an exchange. | 12:00 - 20:00 |
swap.status |
enum |
Required | No | Standard | New coverage-request status. | APPROVED |
previous_status |
enum |
Required | No | Standard | Status before approval. | TARGET_ACCEPTED |
approved_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
approved_at |
date-time |
Required | No | Standard | ISO 8601 approval timestamp. | 2026-08-20T09:05:11-05:00 |
Payload produced after a manager rejects a shift swap or shift-board pickup. Free-text notes are intentionally excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
swap.id |
integer |
Required | No | Standard | Coverage-request ID. | 285 |
swap.request_type |
enum |
Required | No | Standard | Swap or give-away request type. | SWAP |
swap.requester_id |
integer |
Required | No | Standard | Requesting employee ID. | 42 |
swap.requester_name |
string |
Required | Yes | Standard | Requesting employee display name when available. | Jordan Lee |
swap.requester_shift_id |
integer |
Required | No | Standard | Requester shift ID. | 5512 |
swap.requester_shift_date |
date |
Required | Yes | Standard | Requester shift date when available. | 2026-08-22 |
swap.requester_shift_time |
string |
Required | Yes | Standard | Requester shift time range when available. | 08:00 - 16:00 |
swap.target_id |
integer |
Required | No | Standard | Receiving employee ID. | 56 |
swap.target_name |
string |
Required | Yes | Standard | Receiving employee display name when available. | Taylor Morgan |
swap.target_shift_id |
integer |
Required | Yes | Standard | Target shift ID for an exchange. | 5520 |
swap.target_shift_date |
date |
Required | Yes | Standard | Target shift date for an exchange. | 2026-08-23 |
swap.target_shift_time |
string |
Required | Yes | Standard | Target shift time range for an exchange. | 12:00 - 20:00 |
swap.status |
enum |
Required | No | Standard | New coverage-request status. | REJECTED |
previous_status |
enum |
Required | No | Standard | Status before rejection. | TARGET_ACCEPTED |
rejected_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
rejected_at |
date-time |
Required | No | Standard | ISO 8601 rejection timestamp. | 2026-08-20T09:22:05-05:00 |
Optional filter used by employee-associated collection feeds.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee_id |
integer |
Optional | No | Standard | Return rows for one employee. | 42 |
Active employee deduction elections and employer matching amounts.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
data[].employee_name |
string |
Required | No | Standard | Employee name. | Jordan Lee |
data[].employee_payroll_id |
string |
Required | No | Conditional | External payroll identifier, or an empty string. | EE-1042 |
data[].code |
string |
Required | No | Standard | Deduction code. | MEDICAL |
data[].label |
string |
Required | No | Standard | Deduction label. | Medical Plan |
data[].deduction_type |
string |
Required | No | Standard | Configured deduction type. | PRE_TAX |
data[].employee_amount |
number |
Required | No | Sensitive | Employee deduction amount. | 85.25 |
data[].employer_match |
number |
Required | No | Sensitive | Employer matching amount. | 50 |
JSON body assigning or clearing one employee’s external payroll identifier.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
payroll_id |
string |
Required | No | Conditional | External payroll identifier up to 80 characters. Send an empty string to clear it. | EE-1042 |
Employee identity summary after a payroll-ID update.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Employee ID. | 42 |
data.name |
string |
Required | No | Standard | Employee name. | Jordan Lee |
data.email |
string |
Required | No | Standard | Employee email. | jordan.lee@example.com |
data.payroll_id |
string |
Required | No | Conditional | Stored payroll identifier, or an empty string after clearing. | EE-1042 |
data.active |
boolean |
Required | No | Standard | Whether employee status is ACTIVE. | true |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
Payload produced when the primary payroll report is downloaded. It reports export totals and identifiers without including employee rows, rates, earnings, deductions, or bank details.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
export.provider |
string |
Required | No | Standard | Payroll export format/provider key. | generic |
export.company_code |
string |
Required | Yes | Sensitive | Optional external payroll company code. | ACME01 |
export.date_from |
date |
Required | No | Standard | First exported work date. | 2026-08-10 |
export.date_to |
date |
Required | No | Standard | Last exported work date. | 2026-08-23 |
export.filename |
string |
Required | No | Standard | Downloaded filename. | generic_payroll_20260810_20260823.csv |
export.format |
enum |
Required | No | Standard | Selected download format. | csv |
export.row_count |
integer |
Required | No | Standard | Employee/payroll rows exported. | 18 |
export.total_hours |
number |
Required | No | Standard | Aggregate exported hours. | 1284.5 |
export.regular_hours |
number |
Required | No | Standard | Aggregate regular hours. | 1200 |
export.overtime_hours |
number |
Required | No | Standard | Aggregate overtime hours. | 84.5 |
export.double_overtime_hours |
number |
Required | No | Standard | Aggregate double-overtime hours. | 0 |
export.missing_payroll_id_count |
integer |
Required | No | Standard | Rows missing an external payroll identifier. | 0 |
exported_by |
object |
Required | Yes | Standard | Authenticated user that downloaded the export. | {"id":7,"name":"Morgan Ellis"} |
exported_at |
date-time |
Required | No | Standard | ISO 8601 export timestamp. | 2026-08-20T14:05:00-05:00 |
Payload produced when a pending tip pool is approved. It includes the pool-level amount and allocation count, but excludes employee allocations and review notes.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
tip_pool.id |
integer |
Required | No | Standard | Tip-pool ID. | 284 |
tip_pool.pool_date |
date |
Required | No | Standard | Business date represented by the pool. | 2026-08-19 |
tip_pool.work_location_id |
integer |
Required | Yes | Standard | Work-location relationship ID. | 3 |
tip_pool.location |
string |
Required | No | Standard | Resolved work-location label, or an empty string. | Main Office |
tip_pool.shift_label |
string |
Required | No | Standard | Optional shift/daypart label, or an empty string. | Dinner |
tip_pool.total_tips |
number |
Required | No | Sensitive | Approved pool-level tip amount. | 842.35 |
tip_pool.split_method |
string |
Required | No | Standard | Allocation method. | HOURS_WORKED |
tip_pool.payroll_earning_code |
string |
Required | No | Standard | Payroll earning code assigned to the pool. | TIPS |
tip_pool.source_type |
string |
Required | No | Standard | Pool construction source. | POLICY |
tip_pool.allocation_count |
integer |
Required | No | Standard | Employees allocated by the approved pool. | 12 |
tip_pool.status |
enum |
Required | No | Standard | New pool status. | APPROVED |
approved_by |
integer |
Required | Yes | Standard | Reviewing user ID. | 7 |
approved_at |
date-time |
Required | No | Standard | ISO 8601 approval timestamp. | 2026-08-20T15:20:00-05:00 |
Optional filters for listing payroll runs.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
pay_date_from |
date |
Optional | No | Standard | First pay date to include (the period end for a run without a pay date). | 2026-07-01 |
pay_date_to |
date |
Optional | No | Standard | Last pay date to include. | 2026-09-30 |
status |
string |
Optional | No | Standard | Comma-separated statuses: APPROVED, PAYMENT_STAGED, PAID, VOID, and CALCULATED with include_unapproved=1. Defaults to approved, payment staged and paid. | PAID |
include_unapproved |
boolean |
Optional | No | Standard | Also list calculated payrolls not approved yet (and payrolls voided before approval). | 0 |
limit |
integer |
Optional | No | Standard | Page size from 1 to 500. Defaults to 100. | 100 |
after_id |
integer |
Optional | No | Standard | Return runs with an ID greater than this cursor. | 0 |
Payroll runs with company totals, oldest run ID first. No employee data.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<PayrollRun> |
Required | No | Standard | Payroll runs. | [{...}] |
data[].id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
data[].run_code |
string |
Required | No | Standard | Run code used in exports and the audit log. | PAY-20260816-20260831-A1B2C3 |
data[].label |
string |
Required | No | Standard | How AppyShift names the payroll: its pay period, or its type and pay date for an extra payroll. | Aug 16 – 31, 2026 |
data[].run_type |
enum |
Required | No | Standard | REGULAR, BONUS, CORRECTION, SUPPLEMENTAL or OFF_CYCLE. | REGULAR |
data[].status |
enum |
Required | No | Standard | APPROVED, PAYMENT_STAGED, PAID, VOID, or CALCULATED (only with include_unapproved=1). | PAID |
data[].period_start |
date |
Required | Yes | Standard | First day of the pay period. | 2026-08-16 |
data[].period_end |
date |
Required | Yes | Standard | Last day of the pay period. | 2026-08-31 |
data[].pay_date |
date |
Required | Yes | Standard | Pay date (check date). | 2026-09-04 |
data[].employee_count |
integer |
Required | No | Standard | Pay statements on the run. | 18 |
data[].gross_pay |
number |
Required | No | Standard | Total gross pay. | 42810.55 |
data[].employee_taxes |
number |
Required | No | Standard | Total taxes withheld from employees. | 6120.4 |
data[].employer_taxes |
number |
Required | No | Standard | Total employer taxes. | 3488.12 |
data[].deductions |
number |
Required | No | Standard | Total pre-tax and after-tax deductions. | 2210 |
data[].net_pay |
number |
Required | No | Standard | Total net pay. | 34480.15 |
data[].approved_at |
date-time |
Required | Yes | Standard | When the payroll was approved. | 2026-09-02 15:41:09 |
data[].paid_at |
date-time |
Required | Yes | Standard | When the payroll was marked paid. | 2026-09-04 09:02:44 |
data[].voided_at |
date-time |
Required | Yes | Standard | When the payroll was voided (status VOID). | null |
data[].correction |
boolean |
Required | No | Standard | True for a CORRECTION run. | false |
data[].void_reversal |
boolean |
Required | No | Standard | True for the reversing payroll AppyShift adds when a paid pay statement is voided. Its amounts are negative. | false |
data[].voided_statement_count |
integer |
Required | No | Standard | Pay statements on this run voided after it was paid. | 0 |
meta.row_count |
integer |
Required | No | Standard | Runs returned. | 1 |
meta.statuses |
array<string> |
Required | No | Standard | Statuses applied. | ["APPROVED","PAYMENT_STAGED","PAID"] |
meta.include_unapproved |
boolean |
Required | No | Standard | Whether calculated payrolls were included. | false |
meta.pay_date_from |
date |
Required | Yes | Standard | Applied pay date start. | 2026-07-01 |
meta.pay_date_to |
date |
Required | Yes | Standard | Applied pay date end. | 2026-09-30 |
meta.pagination.limit |
integer |
Required | No | Standard | Applied page size. | 100 |
meta.pagination.has_more |
boolean |
Required | No | Standard | Whether another page exists. | false |
meta.pagination.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id to read the next page. | null |
Options for one payroll run and its pay statements.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
include_unapproved |
boolean |
Optional | No | Standard | Allow a calculated payroll that is not approved yet. | 0 |
limit |
integer |
Optional | No | Standard | Statements only: page size from 1 to 500. Defaults to 100. | 100 |
after_id |
integer |
Optional | No | Standard | Statements only: return statements with an ID greater than this cursor. | 0 |
One payroll run with totals by earning code, deduction code and tax. Company totals only.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
data.run_code |
string |
Required | No | Standard | Run code used in exports and the audit log. | PAY-20260816-20260831-A1B2C3 |
data.label |
string |
Required | No | Standard | How AppyShift names the payroll: its pay period, or its type and pay date for an extra payroll. | Aug 16 – 31, 2026 |
data.run_type |
enum |
Required | No | Standard | REGULAR, BONUS, CORRECTION, SUPPLEMENTAL or OFF_CYCLE. | REGULAR |
data.status |
enum |
Required | No | Standard | APPROVED, PAYMENT_STAGED, PAID, VOID, or CALCULATED (only with include_unapproved=1). | PAID |
data.period_start |
date |
Required | Yes | Standard | First day of the pay period. | 2026-08-16 |
data.period_end |
date |
Required | Yes | Standard | Last day of the pay period. | 2026-08-31 |
data.pay_date |
date |
Required | Yes | Standard | Pay date (check date). | 2026-09-04 |
data.employee_count |
integer |
Required | No | Standard | Pay statements on the run. | 18 |
data.gross_pay |
number |
Required | No | Standard | Total gross pay. | 42810.55 |
data.employee_taxes |
number |
Required | No | Standard | Total taxes withheld from employees. | 6120.4 |
data.employer_taxes |
number |
Required | No | Standard | Total employer taxes. | 3488.12 |
data.deductions |
number |
Required | No | Standard | Total pre-tax and after-tax deductions. | 2210 |
data.net_pay |
number |
Required | No | Standard | Total net pay. | 34480.15 |
data.approved_at |
date-time |
Required | Yes | Standard | When the payroll was approved. | 2026-09-02 15:41:09 |
data.paid_at |
date-time |
Required | Yes | Standard | When the payroll was marked paid. | 2026-09-04 09:02:44 |
data.voided_at |
date-time |
Required | Yes | Standard | When the payroll was voided (status VOID). | null |
data.correction |
boolean |
Required | No | Standard | True for a CORRECTION run. | false |
data.void_reversal |
boolean |
Required | No | Standard | True for the reversing payroll AppyShift adds when a paid pay statement is voided. Its amounts are negative. | false |
data.voided_statement_count |
integer |
Required | No | Standard | Pay statements on this run voided after it was paid. | 0 |
data.statement_count |
integer |
Required | No | Standard | Pay statements on the run. | 18 |
data.hours |
number |
Required | No | Standard | Total hours paid. | 1462.5 |
data.earnings_by_code[].code |
string |
Required | Yes | Standard | Earning code, or null for a line without one. | REG |
data.earnings_by_code[].label |
string |
Required | No | Standard | Earning label. | Regular Pay |
data.earnings_by_code[].type |
enum |
Required | No | Standard | REGULAR, OVERTIME, DOUBLE_OVERTIME, EXTRA, TIPS, REIMBURSEMENT, ADJUSTMENT or OTHER. | REGULAR |
data.earnings_by_code[].hours |
number |
Required | No | Standard | Hours on the code. | 1380 |
data.earnings_by_code[].amount |
number |
Required | No | Standard | Amount on the code. | 39960.55 |
data.earnings_by_code[].statement_count |
integer |
Required | No | Standard | Statements with the code. | 18 |
data.deductions_by_code[].code |
string |
Required | Yes | Standard | Deduction code, or null for a line without one. | K401 |
data.deductions_by_code[].label |
string |
Required | No | Standard | Deduction label. | 401(k) |
data.deductions_by_code[].type |
enum |
Required | No | Standard | PRE_TAX, POST_TAX, GARNISHMENT, BENEFIT or OTHER. | PRE_TAX |
data.deductions_by_code[].employee_amount |
number |
Required | No | Standard | Amount taken from employees. | 2210 |
data.deductions_by_code[].employer_amount |
number |
Required | No | Standard | Employer share recorded on the lines, or 0. | 0 |
data.deductions_by_code[].statement_count |
integer |
Required | No | Standard | Statements with the code. | 11 |
data.taxes_by_tax[].name |
string |
Required | No | Standard | Tax name as calculated. | Social Security |
data.taxes_by_tax[].code |
enum |
Required | No | Standard | Tax code: FIT, SS, MED, ADDL_MED, FUTA, BWH, SIT, SUI, SDI, STT, CCC, ETT, JDF, LOCAL or OTHER. | SS |
data.taxes_by_tax[].scope |
enum |
Required | No | Standard | FEDERAL, STATE, LOCAL, FICA, MEDICARE, UNEMPLOYMENT or OTHER. | FICA |
data.taxes_by_tax[].jurisdiction |
string |
Required | Yes | Standard | Jurisdiction, such as US, a state or a locality. | US |
data.taxes_by_tax[].taxable_wages |
number |
Required | No | Standard | Taxable wages, counted once per statement. | 40600.55 |
data.taxes_by_tax[].employee_amount |
number |
Required | No | Standard | Withheld from employees. | 2517.23 |
data.taxes_by_tax[].employer_amount |
number |
Required | No | Standard | Paid by the employer. | 2517.23 |
Each employee's pay statement on a run. Needs payroll.statements:read. Never includes Social Security numbers, addresses, bank, routing or account numbers.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Pay statement ID. | 90412 |
data[].run_id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
data[].employee_id |
integer |
Required | Yes | Standard | AppyShift employee ID. | 42 |
data[].employee_payroll_id |
string |
Required | Yes | Conditional | The employee's payroll ID. | EE-1042 |
data[].employee_name |
string |
Required | No | Standard | Employee name on the statement. | Jordan Lee |
data[].department |
string |
Required | Yes | Standard | Department on the statement. | Front Desk |
data[].hours |
number |
Required | No | Sensitive | Hours paid. | 80 |
data[].gross_pay |
number |
Required | No | Sensitive | Gross pay. | 1760 |
data[].pre_tax_deductions |
number |
Required | No | Sensitive | Pre-tax deductions. | 50 |
data[].post_tax_deductions |
number |
Required | No | Sensitive | After-tax deductions, garnishments included. | 0 |
data[].employee_taxes |
number |
Required | No | Sensitive | Taxes withheld. | 290.48 |
data[].employer_taxes |
number |
Required | No | Sensitive | Employer taxes. | 134.64 |
data[].net_pay |
number |
Required | No | Sensitive | Net pay. | 1419.52 |
data[].payment_method |
enum |
Required | Yes | Standard | CHECK, ACH or MANUAL; null when not paid. Never an account or routing number. | ACH |
data[].check_number |
string |
Required | Yes | Standard | Check number of a printed check, or the number of a check written by hand. | null |
data[].voided |
boolean |
Required | No | Standard | The statement was voided after the payroll was paid. | false |
data[].void_reversal |
boolean |
Required | No | Standard | The reversing statement of a voided one (negative amounts). | false |
data[].earnings[].code |
string |
Required | Yes | Standard | Earning code. | REG |
data[].earnings[].label |
string |
Required | No | Standard | Earning label. | Regular Pay |
data[].earnings[].type |
enum |
Required | No | Standard | Earning type. | REGULAR |
data[].earnings[].hours |
number |
Required | No | Sensitive | Hours. | 80 |
data[].earnings[].rate |
number |
Required | Yes | Sensitive | Rate as stored on the line. Some overtime and double-time lines store the base rate and others the rate with its multiplier; use effective_rate to show a rate. | 22 |
data[].earnings[].effective_rate |
number |
Required | Yes | Sensitive | The rate the amount was worked out at (hours x effective_rate = amount), as the pay statement and reports show it: 36.75 for 0.5 overtime hours paid $18.38 on a $24.50 base. Added 2026-10-26. | 22 |
data[].earnings[].amount |
number |
Required | No | Sensitive | Amount. | 1760 |
data[].earnings[].taxable |
boolean |
Required | No | Standard | Whether the earning is taxable. | true |
data[].earnings[].non_cash |
boolean |
Required | No | Standard | Taxed but not paid in the paycheck, such as cash tips. | false |
data[].deductions[].code |
string |
Required | Yes | Standard | Deduction code. | K401 |
data[].deductions[].label |
string |
Required | No | Standard | Deduction label. | 401(k) |
data[].deductions[].type |
enum |
Required | No | Standard | PRE_TAX, POST_TAX, GARNISHMENT, BENEFIT or OTHER. | PRE_TAX |
data[].deductions[].employee_amount |
number |
Required | No | Sensitive | Taken from the employee. | 50 |
data[].deductions[].employer_amount |
number |
Required | No | Sensitive | Employer share recorded on the line, or 0. | 0 |
data[].taxes[].name |
string |
Required | No | Standard | Tax name. | Medicare |
data[].taxes[].code |
enum |
Required | No | Standard | Tax code (see PayrollRunDetailResponse). | MED |
data[].taxes[].scope |
enum |
Required | No | Standard | Tax scope. | MEDICARE |
data[].taxes[].jurisdiction |
string |
Required | Yes | Standard | Jurisdiction. | US |
data[].taxes[].taxable_wages |
number |
Required | No | Sensitive | Taxable wages. | 1760 |
data[].taxes[].employee_amount |
number |
Required | No | Sensitive | Withheld. | 25.52 |
data[].taxes[].employer_amount |
number |
Required | No | Sensitive | Employer amount. | 25.52 |
meta.run_id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
meta.run_status |
enum |
Required | No | Standard | The run's status. | PAID |
meta.row_count |
integer |
Required | No | Standard | Statements returned. | 1 |
meta.pagination.limit |
integer |
Required | No | Standard | Applied page size. | 100 |
meta.pagination.has_more |
boolean |
Required | No | Standard | Whether another page exists. | false |
meta.pagination.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id to read the next page. | null |
The quarter for tax liabilities and deposits. Defaults to the current quarter in the company time zone.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
year |
integer |
Optional | No | Standard | Four-digit year. | 2026 |
quarter |
integer |
Optional | No | Standard | 1, 2, 3 or 4. | 3 |
include_unapproved |
boolean |
Optional | No | Standard | Liabilities only: add calculated payrolls not approved yet. | 0 |
Tax liability by tax and jurisdiction for payrolls paid in the quarter.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.year |
integer |
Required | No | Standard | Year. | 2026 |
data.quarter |
integer |
Required | No | Standard | Quarter. | 3 |
data.period_start |
date |
Required | No | Standard | First day of the quarter. | 2026-07-01 |
data.period_end |
date |
Required | No | Standard | Last day of the quarter. | 2026-09-30 |
data.lines[].code |
enum |
Required | No | Standard | Tax code: FIT, SS, MED, ADDL_MED, FUTA, BWH, SIT, SUI, SDI, STT, CCC, ETT, JDF, LOCAL or OTHER. | SS |
data.lines[].tax |
string |
Required | No | Standard | Tax name. | Social Security |
data.lines[].jurisdiction |
string |
Required | No | Standard | US, a state code or a locality. | US |
data.lines[].taxable_wages |
number |
Required | No | Standard | Taxable wages, counted once per statement. | 128431.65 |
data.lines[].employee_amount |
number |
Required | No | Standard | Withheld from employees. | 7962.76 |
data.lines[].employer_amount |
number |
Required | No | Standard | Employer amount. | 7962.76 |
data.lines[].total |
number |
Required | No | Standard | Employee plus employer. | 15925.52 |
data.lines[].employee_count |
integer |
Required | No | Standard | Employees with the tax. | 18 |
data.lines[].lines_changed_by_hand |
integer |
Required | No | Standard | Statement lines changed by hand. | 0 |
data.totals.employee_amount |
number |
Required | No | Standard | Total withheld. | 17278.27 |
data.totals.employer_amount |
number |
Required | No | Standard | Total employer taxes. | 7962.76 |
data.totals.total |
number |
Required | No | Standard | Total liability. | 25241.03 |
data.statement_count |
integer |
Required | No | Standard | Pay statements counted. | 54 |
data.employee_count |
integer |
Required | No | Standard | Employees counted. | 18 |
data.payrolls[].run_id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
data.payrolls[].run_code |
string |
Required | No | Standard | Run code. | PAY-20260816-20260831-A1B2C3 |
data.payrolls[].label |
string |
Required | No | Standard | Payroll name. | Aug 16 – 31, 2026 |
data.payrolls[].status |
enum |
Required | No | Standard | Run status. | PAID |
data.payrolls[].pay_date |
date |
Required | Yes | Standard | Pay date. | 2026-09-04 |
data.payrolls[].employee_taxes |
number |
Required | No | Standard | Taxes withheld on the payroll. | 6120.4 |
data.payrolls[].employer_taxes |
number |
Required | No | Standard | Employer taxes on the payroll. | 3488.12 |
data.payrolls[].federal_deposit_taxes |
number |
Required | No | Standard | Form 941 taxes: federal income tax and both halves of Social Security and Medicare. | 8721.6 |
meta.include_unapproved |
boolean |
Required | No | Standard | Whether calculated payrolls were counted. | false |
meta.warnings |
array<string> |
Required | No | Standard | Notes such as payrolls not approved yet or lines changed by hand. | [] |
Tax deposits due for the quarter and the year's FUTA deposits, with what the company recorded as deposited.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.year |
integer |
Required | No | Standard | Year. | 2026 |
data.quarter |
integer |
Required | No | Standard | Quarter. | 3 |
data.period_start |
date |
Required | No | Standard | First day of the quarter. | 2026-07-01 |
data.period_end |
date |
Required | No | Standard | Last day of the quarter. | 2026-09-30 |
data.filer_form |
enum |
Required | No | Standard | 941 or 944. | 941 |
data.deposit_schedule |
enum |
Required | No | Standard | MONTHLY or SEMIWEEKLY. | MONTHLY |
data.deposits[].kind |
string |
Required | No | Standard | Deposit kind: 941, 944, 940, STATE_WITHHOLDING, SUI, LOCAL or a state contribution. | 941 |
data.deposits[].tax |
string |
Required | No | Standard | Deposit name. | Federal payroll taxes (Form 941) |
data.deposits[].jurisdiction |
string |
Required | No | Standard | US, a state code or a local tax code. | US |
data.deposits[].period_start |
date |
Required | Yes | Standard | First day of the liability period. | 2026-08-01 |
data.deposits[].period_end |
date |
Required | Yes | Standard | Last day of the liability period. | 2026-08-31 |
data.deposits[].rule |
string |
Required | No | Standard | NEXT_DAY, SEMIWEEKLY, MONTHLY, QUARTERLY, ANNUAL, FUTA, or the state schedule. | MONTHLY |
data.deposits[].due_date |
date |
Required | Yes | Standard | Due date. | 2026-09-15 |
data.deposits[].amount |
number |
Required | No | Standard | Amount owed for the period. | 8721.6 |
data.deposits[].recorded |
number |
Required | No | Standard | Amount the company recorded as deposited. | 8721.6 |
data.deposits[].balance |
number |
Required | No | Standard | Amount owed minus recorded. | 0 |
data.deposits[].status |
enum |
Required | No | Standard | due, partial, overdue, scheduled (recorded for a date after today), paid, late or none. | scheduled |
data.deposits[].status_label |
string |
Required | No | Standard | Status as the Taxes section shows it. | Scheduled for Sep 14 |
data.deposits[].next_day |
boolean |
Required | No | Standard | A $100,000 next-day deposit. | false |
data.deposits[].breakdown |
array<object> |
Required | No | Standard | What the deposit is made of when it carries more than one tax: label and amount. | [] |
meta.as_of |
date |
Required | No | Standard | The date statuses are worked out for (company time zone). | 2026-09-10 |
meta.row_count |
integer |
Required | No | Standard | Deposits returned. | 1 |
meta.warnings |
array<string> |
Required | No | Standard | Notes such as past-due deposits or states not set up. | [] |
Either a pay date range or one payroll run.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
pay_date_from |
date |
Optional | No | Standard | First pay date. Required without run_id. | 2026-09-01 |
pay_date_to |
date |
Optional | No | Standard | Last pay date, at most 366 days after pay_date_from. Required without run_id. | 2026-09-30 |
run_id |
integer |
Optional | No | Standard | One approved, payment staged or paid payroll run. | 318 |
One journal entry per payroll, dated on its pay date, as the General ledger detail report shows it.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].run_id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
data[].run_code |
string |
Required | No | Standard | Run code. | PAY-20260816-20260831-A1B2C3 |
data[].label |
string |
Required | No | Standard | Payroll name. | Aug 16 – 31, 2026 |
data[].run_type |
enum |
Required | No | Standard | Run type. | REGULAR |
data[].entry_date |
date |
Required | Yes | Standard | Journal entry date (the pay date). | 2026-09-04 |
data[].total_debit |
number |
Required | No | Standard | Entry debits. | 46298.67 |
data[].total_credit |
number |
Required | No | Standard | Entry credits. | 46298.67 |
data[].balanced |
boolean |
Required | No | Standard | Debits equal credits. | true |
data[].lines[].account |
string |
Required | No | Standard | GL account number, or Unmapped. | 6000 |
data[].lines[].account_name |
string |
Required | No | Standard | GL account name. | Wages Expense |
data[].lines[].department |
string |
Required | Yes | Standard | Department on the pay statements. | Front Desk |
data[].lines[].memo |
string |
Required | No | Standard | What the line is for, such as an earning code, a tax or net pay. | Earnings: Regular Pay (REG) |
data[].lines[].debit |
number |
Required | No | Standard | Debit amount, or 0. | 12410 |
data[].lines[].credit |
number |
Required | No | Standard | Credit amount, or 0. | 0 |
data[].lines[].mapped |
boolean |
Required | No | Standard | False when no GL account is set up for the line. | true |
data[].lines[].default_account |
boolean |
Required | No | Standard | AppyShift's default account was used (none set in Payroll setup). | false |
meta.row_count |
integer |
Required | No | Standard | Journal entries returned. | 1 |
meta.run_id |
integer |
Required | Yes | Standard | Requested run, when one was. | null |
meta.pay_date_from |
date |
Required | Yes | Standard | Applied range start. | 2026-09-01 |
meta.pay_date_to |
date |
Required | Yes | Standard | Applied range end. | 2026-09-30 |
meta.totals.debit |
number |
Required | No | Standard | Total debits. | 46298.67 |
meta.totals.credit |
number |
Required | No | Standard | Total credits. | 46298.67 |
meta.totals.difference |
number |
Required | No | Standard | Debits minus credits. | 0 |
meta.totals.balanced |
boolean |
Required | No | Standard | Every entry balances. | true |
meta.totals.unmapped_amount |
number |
Required | No | Standard | Amount on lines without a GL account. | 0 |
meta.totals.unmapped_lines |
integer |
Required | No | Standard | Lines without a GL account. | 0 |
Payload of payroll.run.approved and payroll.run.paid: the payroll run with company totals. No employee names, statements, pay rates or bank details.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
run.id |
integer |
Required | No | Standard | Payroll run ID. | 318 |
run.run_code |
string |
Required | No | Standard | Run code used in exports and the audit log. | PAY-20260816-20260831-A1B2C3 |
run.label |
string |
Required | No | Standard | How AppyShift names the payroll: its pay period, or its type and pay date for an extra payroll. | Aug 16 – 31, 2026 |
run.run_type |
enum |
Required | No | Standard | REGULAR, BONUS, CORRECTION, SUPPLEMENTAL or OFF_CYCLE. | REGULAR |
run.status |
enum |
Required | No | Standard | APPROVED, PAYMENT_STAGED, PAID, VOID, or CALCULATED (only with include_unapproved=1). | PAID |
run.period_start |
date |
Required | Yes | Standard | First day of the pay period. | 2026-08-16 |
run.period_end |
date |
Required | Yes | Standard | Last day of the pay period. | 2026-08-31 |
run.pay_date |
date |
Required | Yes | Standard | Pay date (check date). | 2026-09-04 |
run.employee_count |
integer |
Required | No | Standard | Pay statements on the run. | 18 |
run.gross_pay |
number |
Required | No | Standard | Total gross pay. | 42810.55 |
run.employee_taxes |
number |
Required | No | Standard | Total taxes withheld from employees. | 6120.4 |
run.employer_taxes |
number |
Required | No | Standard | Total employer taxes. | 3488.12 |
run.deductions |
number |
Required | No | Standard | Total pre-tax and after-tax deductions. | 2210 |
run.net_pay |
number |
Required | No | Standard | Total net pay. | 34480.15 |
run.approved_at |
date-time |
Required | Yes | Standard | When the payroll was approved. | 2026-09-02 15:41:09 |
run.paid_at |
date-time |
Required | Yes | Standard | When the payroll was marked paid. | 2026-09-04 09:02:44 |
run.voided_at |
date-time |
Required | Yes | Standard | When the payroll was voided (status VOID). | null |
run.correction |
boolean |
Required | No | Standard | True for a CORRECTION run. | false |
run.void_reversal |
boolean |
Required | No | Standard | True for the reversing payroll AppyShift adds when a paid pay statement is voided. Its amounts are negative. | false |
run.voided_statement_count |
integer |
Required | No | Standard | Pay statements on this run voided after it was paid. | 0 |
Optional query parameter controlling sensitive saved definitions, datasets, and columns.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
include_sensitive |
boolean |
Optional | No | Sensitive | Set to 1 only with reports.sensitive:read. | 0 |
Saved report definitions plus the datasets and columns currently available to the token.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<SavedReport> |
Required | No | Conditional | Saved report definitions filtered to authorized columns. | [{...}] |
data[].id |
integer |
Required | No | Standard | Saved report ID accepted by ReportRunRequest.report_id. | 18 |
data[].name |
string |
Required | No | Standard | Saved report name. | Active employee roster |
data[].description |
string |
Required | No | Standard | Saved report description. | Current employees for payroll review |
data[].dataset |
string |
Required | No | Standard | Dataset key. | employee_roster |
data[].columns |
array<string> |
Required | No | Conditional | Authorized base column keys selected by the saved report. | ["employee_name","department"] |
data[].column_formats |
object<string, string> |
Required | No | Standard | Format key by base column. | {"employee_name":"last_first"} |
data[].filters |
object |
Required | No | Conditional | Stored dataset filters after authorization filtering. | {"status":"ACTIVE"} |
data[].updated_at |
date-time |
Required | No | Standard | Last saved-definition update timestamp. | 2026-08-18 11:45:00 |
datasets |
object<string, DatasetDefinition> |
Required | No | Conditional | Dataset definitions keyed by dataset name. | {"employee_roster":{...}} |
datasets.{dataset}.label |
string |
Required | No | Standard | Dataset display label. | Employee roster |
datasets.{dataset}.date_enabled |
boolean |
Required | No | Standard | Whether the dataset accepts date-range filters. | false |
datasets.{dataset}.default_columns |
array<string> |
Required | No | Conditional | Default authorized column keys. | ["employee_name","department"] |
datasets.{dataset}.columns |
object<string, object> |
Required | No | Conditional | Authorized column definitions keyed by field name. | {"employee_name":{...}} |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.row_count |
integer |
Required | No | Standard | Saved reports returned. | 1 |
meta.sensitive_fields_included |
boolean |
Required | No | Standard | Whether sensitive definitions were authorized and included. | false |
JSON body for a saved or ad-hoc report. Ad-hoc selections override the corresponding saved-report values.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
report_id |
integer |
Optional | No | Standard | Saved report ID. Optional when dataset and columns are supplied directly. | 18 |
dataset |
string |
Optional | No | Standard | Dataset key. Defaults to the saved report or employee_roster. | employee_roster |
columns |
array<string> |
Optional | No | Conditional | Authorized base column keys to return. | ["employee_name","department"] |
column_formats |
object<string, string> |
Optional | No | Standard | Format key by selected base column. | {"employee_name":"last_first"} |
column_labels |
object<string, string> |
Optional | No | Standard | Optional output labels keyed by base column. | {"employee_name":"Team member"} |
filters |
object |
Optional | No | Conditional | Dataset-specific filters. Values are validated and filtered by the reporting service. | {"status":"ACTIVE"} |
metadata |
object<string, scalar|null> |
Optional | No | Conditional | Opaque client correlation data echoed as meta.client_metadata. Use up to 50 flat entries; keys are limited to 64 characters, string values to 1,000 bytes, and the object to 16 KB. | {"workflow_run_id":"sync_2026_08_19_001"} |
include_sensitive |
boolean |
Optional | No | Sensitive | Set to true only with reports.sensitive:read. | false |
Projected report rows and metadata describing the exact output columns.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<object> |
Required | No | Conditional | Rows keyed by selected output field. Shape and sensitivity depend on the request. | [{"department":"Front Desk"}] |
data[].{output_field} |
scalar|null |
Required | Yes | Conditional | Formatted report cell. Classification inherits from its selected column. | Front Desk |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.report_id |
integer |
Required | Yes | Standard | Saved report ID, or null for an ad-hoc run. | 18 |
meta.dataset |
string |
Required | No | Standard | Dataset that produced the result. | employee_roster |
meta.row_count |
integer |
Required | No | Standard | Rows returned. | 1 |
meta.columns |
array<OutputColumn> |
Required | No | Conditional | Ordered output keys and labels. | [{...}] |
meta.columns[].key |
string |
Required | No | Conditional | Property name used in each data row. | employee_last_first |
meta.columns[].label |
string |
Required | No | Standard | Resolved column label. | Employee |
meta.sensitive_fields_included |
boolean |
Required | No | Standard | Whether sensitive fields were authorized and included. | false |
meta.client_metadata |
object<string, scalar|null> |
Required | No | Conditional | Validated request metadata echoed unchanged, or an empty object when omitted. AppyShift does not interpret or persist these values. | {"workflow_run_id":"sync_2026_08_19_001"} |
Query parameters for listing shout-outs.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
created_from |
date |
Optional | No | Standard | First included day (YYYY-MM-DD). | 2026-10-01 |
created_to |
date |
Optional | No | Standard | Last included day (YYYY-MM-DD). | 2026-10-31 |
employee_id |
integer |
Optional | No | Standard | Only shout-outs sent to or by this employee. Another company's ID answers 404. | 57 |
status |
enum |
Optional | No | Standard | published (default), pending, hidden, rejected or all. | published |
limit |
integer |
Optional | No | Standard | Page size, 1 to 500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Return shout-outs after this ID (meta.pagination.next_after_id). | 5120 |
JSON body for sending a shout-out. Unknown fields answer 422 unknown_field; nothing is saved unless every check passes.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
to_employee_ids |
array<integer> |
Required | No | Standard | The coworkers to recognize (1 to 25): active employees of this company, not the sender. Each gets their own shout-out. | [57] |
message |
string |
Required | No | Standard | What they did, up to 4,000 characters (HTML is removed). | Covered my Saturday close on short notice. |
from_employee_id |
integer |
Optional | Yes | Standard | The employee sending it. Leave it out to send from the company under your integration's name. | 42 |
value |
string |
Optional | Yes | Standard | What it recognizes: a key from GET /api/v1/recognition/values. | COVERED_SHIFT |
points |
integer |
Optional | Yes | Standard | Points for each coworker from the sender's monthly bank (needs from_employee_id and points on). Over the company's limits answers 422 points_over_limit, points_over_budget or points_not_allowed. | 20 |
award |
enum |
Optional | Yes | Standard | The company's award for a company shout-out: manager_recognition or customer_compliment, at the amount set in Recognition & Rewards. | customer_compliment |
Shout-outs, as listed or as just sent.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Shout-out ID (a post on the company board). | 5120 |
data[].created_at |
date-time |
Required | No | Standard | When it was sent. | 2026-10-16 09:12:44 |
data[].status |
enum |
Required | No | Standard | PUBLISHED, PENDING (waiting for a manager), HIDDEN or REJECTED. | PUBLISHED |
data[].visibility |
enum |
Required | No | Standard | everyone (live on the board) or managers (only the company's managers see it). | everyone |
data[].from.type |
enum |
Required | No | Standard | employee, staff (a manager or admin) or company (sent by an integration). | employee |
data[].from.employee_id |
integer |
Required | Yes | Standard | The sending employee, or null when staff or the company sent it. | 42 |
data[].from.name |
string |
Required | No | Standard | Sender name as shown on the board (the integration's name for company shout-outs). | Avery Stone |
data[].to_employees |
array<object> |
Required | No | Standard | The recognized coworker: id and name. | [{"id":57,"name":"Jordan Lee"}] |
data[].message |
string |
Required | No | Standard | What they did, as written. | Covered my Saturday close on short notice. |
data[].value |
object |
Required | Yes | Standard | What it recognizes: key and label (GET /api/v1/recognition/values), or null. | {"key":"COVERED_SHIFT","label":"Covered a shift"} |
data[].points_awarded |
integer |
Required | No | Standard | Points posted to the coworker with this shout-out. | 20 |
data[].points_pending |
integer |
Required | No | Standard | Points waiting for a manager's approval. | 0 |
meta.pagination.next_after_id |
integer |
Optional | Yes | Standard | Cursor for the next page, or null on the last page (list only). | 5120 |
meta.created_count |
integer |
Optional | No | Standard | How many shout-outs were sent (POST only). | 1 |
Points balances per employee. Points have no cash value; rewards with cash value go through payroll.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].employee.id |
integer |
Required | No | Standard | Employee ID. | 57 |
data[].employee.name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
data[].earned |
integer |
Required | No | Standard | Points from shout-outs, awards and adjustments. | 145 |
data[].redeemed |
integer |
Required | No | Standard | Points held or spent on rewards (a declined request gives them back). | 100 |
data[].available |
integer |
Required | No | Standard | Points they can spend now (earned minus redeemed). | 45 |
data[].pending |
integer |
Required | No | Standard | Points waiting for a manager's approval. | 0 |
meta.points_enabled |
boolean |
Required | No | Standard | Whether points are on for the company. | true |
The badge catalog, or one employee's progress when employee_id is given.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].key |
string |
Required | No | Standard | Badge key. | shift_saver |
data[].name |
string |
Required | No | Standard | Badge name. | Shift Saver |
data[].emoji |
string |
Required | No | Standard | Badge emoji. | 🛟 |
data[].tiers |
array<integer> |
Optional | No | Standard | Counts that earn each level (catalog). | [1, 5, 10, 25] |
data[].unit |
string |
Required | No | Standard | What is counted. | called-out shifts picked up |
data[].count |
integer |
Optional | No | Standard | The employee's count (with employee_id). | 6 |
data[].earned |
boolean |
Optional | No | Standard | Whether the employee has the badge (with employee_id). | true |
data[].level |
integer |
Optional | No | Standard | Level reached, 0 when not earned (with employee_id). | 2 |
data[].next_tier |
integer |
Optional | Yes | Standard | Count for the next level, or null at the top (with employee_id). | 10 |
meta.badges_enabled |
boolean |
Required | No | Standard | Whether the company shows badges. | true |
The company's rewards store.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Reward ID. | 12 |
data[].name |
string |
Required | No | Standard | Reward name. | $25 gift card |
data[].points_cost |
integer |
Required | No | Standard | Point price. | 250 |
data[].type |
enum |
Required | No | Standard | ITEM, CASH (taxable pay through payroll) or PTO. | CASH |
data[].cash_value |
number |
Required | Yes | Standard | Dollar value of a CASH reward, otherwise null. | 25 |
data[].pto_hours |
number |
Required | Yes | Standard | Hours of a PTO reward, otherwise null. | null |
data[].stock |
integer |
Required | Yes | Standard | How many are left, or null for no limit. | null |
data[].active |
boolean |
Required | No | Standard | Whether employees can see it. | true |
data[].has_picture |
boolean |
Required | No | Standard | Whether it has a picture (shown only to signed-in people). | true |
meta.rewards_store_open |
boolean |
Required | No | Standard | Whether employees can redeem rewards now. | true |
Reward requests and managers' decisions.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Request ID. | 88 |
data[].employee |
object |
Required | No | Standard | The employee: id and name. | {"id":57,"name":"Jordan Lee"} |
data[].reward |
object |
Required | No | Standard | The reward as requested: id, name and type. | {"id":12,"name":"$25 gift card","type":"CASH"} |
data[].points |
integer |
Required | No | Standard | Points held for it. | 250 |
data[].status |
enum |
Required | No | Standard | REQUESTED, FULFILLED or DECLINED (points given back). | REQUESTED |
data[].requested_at |
date-time |
Required | No | Standard | When it was requested. | 2026-10-15 17:40:03 |
data[].decided_at |
date-time |
Required | Yes | Standard | When a manager decided, or null. | null |
data[].decided_by_name |
string |
Required | Yes | Standard | Who decided, or null. | null |
What a shout-out can recognize.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].key |
string |
Required | No | Standard | The key POST accepts as value. | COVERED_SHIFT |
data[].label |
string |
Required | No | Standard | The label shown on the board. | Covered a shift |
Payload sent when a shout-out goes live on the board: sent in the app or the API, or approved by a manager after waiting.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
shout_out.id |
integer |
Required | No | Standard | Shout-out ID (a post on the company board). | 5120 |
shout_out.created_at |
date-time |
Required | No | Standard | When it was sent. | 2026-10-16 09:12:44 |
shout_out.status |
enum |
Required | No | Standard | PUBLISHED, PENDING (waiting for a manager), HIDDEN or REJECTED. | PUBLISHED |
shout_out.visibility |
enum |
Required | No | Standard | everyone (live on the board) or managers (only the company's managers see it). | everyone |
shout_out.from.type |
enum |
Required | No | Standard | employee, staff (a manager or admin) or company (sent by an integration). | employee |
shout_out.from.employee_id |
integer |
Required | Yes | Standard | The sending employee, or null when staff or the company sent it. | 42 |
shout_out.from.name |
string |
Required | No | Standard | Sender name as shown on the board (the integration's name for company shout-outs). | Avery Stone |
shout_out.to_employees |
array<object> |
Required | No | Standard | The recognized coworker: id and name. | [{"id":57,"name":"Jordan Lee"}] |
shout_out.message |
string |
Required | No | Standard | What they did, as written. | Covered my Saturday close on short notice. |
shout_out.value |
object |
Required | Yes | Standard | What it recognizes: key and label (GET /api/v1/recognition/values), or null. | {"key":"COVERED_SHIFT","label":"Covered a shift"} |
shout_out.points_awarded |
integer |
Required | No | Standard | Points posted to the coworker with this shout-out. | 20 |
shout_out.points_pending |
integer |
Required | No | Standard | Points waiting for a manager's approval. | 0 |
source |
enum |
Required | No | Standard | app (the company or employee app) or api. | api |
occurred_at |
date-time |
Required | No | Standard | ISO 8601 time the shout-out went live. | 2026-10-16T09:30:02-05:00 |
Optional filters and cursor for GET /api/v1/jobs.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
status |
enum |
Optional | No | Standard | DRAFT, OPEN, PAUSED, CLOSED or FILLED. Omit for every job. | OPEN |
limit |
integer |
Optional | No | Standard | Page size from 1 to 500; 100 when omitted. | 50 |
after_id |
integer |
Optional | No | Standard | Return jobs with a higher ID (meta.next_after_id of the previous page). | 18 |
Job openings, oldest ID first.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Job ID. | 18 |
data[].title |
string |
Required | No | Standard | Job title. | Line Cook |
data[].status |
enum |
Required | No | Standard | DRAFT, OPEN, PAUSED, CLOSED or FILLED. | OPEN |
data[].employment_type |
enum |
Required | No | Standard | FULL_TIME, PART_TIME, SEASONAL, CONTRACT or TEMPORARY. | FULL_TIME |
data[].workplace_type |
enum |
Required | No | Standard | ONSITE, HYBRID or REMOTE. | ONSITE |
data[].openings |
integer |
Required | No | Standard | Number of people to hire. | 2 |
data[].position |
object |
Required | Yes | Standard | Linked position: id and title, or null. | {"id":4,"title":"Cook"} |
data[].department |
object |
Required | Yes | Standard | Linked department: id and name, or null. | {"id":7,"name":"Kitchen"} |
data[].location |
object |
Required | Yes | Standard | work_location_id (null for a typed-in place), name, city and state, or null. | {"work_location_id":3,"name":"Downtown","city":"Austin","state":"TX"} |
data[].pay |
object |
Required | Yes | Conditional | min, max, period, currency, extras and display, only when the posting shows pay; otherwise null. | {"min":18,"max":22,"period":"HOUR","currency":"USD","extras":[],"display":"$18 - $22 / hour"} |
data[].posted_at |
date-time |
Required | Yes | Standard | When the job was first opened, or null. | 2026-10-01 08:00:00 |
data[].closed_at |
date-time |
Required | Yes | Standard | For a CLOSED or FILLED job, its last change; otherwise null. | null |
data[].created_at |
date-time |
Required | No | Standard | When the job was created. | 2026-09-29 15:20:00 |
data[].updated_at |
date-time |
Required | No | Standard | Last change to the job. | 2026-10-01 08:00:00 |
data[].careers_url |
string |
Required | Yes | Standard | Public careers page for an OPEN job; otherwise null. | https://www.appyshift.com/acme/careers/line-cook |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.row_count |
integer |
Required | No | Standard | Rows in this page. | 2 |
meta.limit |
integer |
Required | No | Standard | Page size used. | 100 |
meta.has_more |
boolean |
Required | No | Standard | Whether another page follows. | false |
meta.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id for the next page, or null. | null |
Optional filters and cursor for GET /api/v1/applicants.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
job_id |
integer |
Optional | No | Standard | Only applications for this job. | 18 |
stage |
enum |
Optional | No | Standard | Only applications in this stage. | INTERVIEW |
updated_since |
date-time |
Optional | No | Standard | Only applications changed at or after this ISO 8601 date or time. | 2026-10-01T00:00:00Z |
limit |
integer |
Optional | No | Standard | Page size from 1 to 500; 100 when omitted. | 100 |
after_id |
integer |
Optional | No | Standard | Return applicants with a higher ID (meta.next_after_id of the previous page). | 5012 |
Applicants, oldest ID first. Details appear only with applicants.sensitive:read.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Applicant ID: one application, a person applying to one job. | 5012 |
data[].candidate_id |
integer |
Required | No | Standard | The person. One candidate can apply to several jobs. | 3307 |
data[].job_id |
integer |
Required | No | Standard | Job the application is for. | 18 |
data[].job_title |
string |
Required | No | Standard | Job title. | Line Cook |
data[].first_name |
string |
Required | No | Standard | First name. | Pat |
data[].last_name |
string |
Required | No | Standard | Last name. | Lee |
data[].email |
string |
Required | No | Standard | Email address, lowercase. | pat.lee@example.com |
data[].phone |
string |
Required | Yes | Standard | Phone number as entered. | 555-123-4567 |
data[].stage |
enum |
Required | No | Standard | NEW, REVIEW, SCREEN, INTERVIEW, OFFER, HIRED, DECLINED or WITHDRAWN. | INTERVIEW |
data[].stage_label |
string |
Required | No | Standard | The company's own name for the stage. | Interview |
data[].source |
string |
Required | No | Standard | Where the application came from. | Indeed |
data[].employee_id |
integer |
Required | Yes | Standard | Employee created when the candidate was hired, or null. | null |
data[].applied_at |
date-time |
Required | No | Standard | When the application arrived. | 2026-10-14 09:12:00 |
data[].updated_at |
date-time |
Required | No | Standard | Last change to the application. | 2026-10-15 16:40:00 |
data[].details |
object |
Optional | No | Sensitive | Present only with applicants.sensitive:read. | {...} |
data[].details.location |
string |
Optional | Yes | Sensitive | Where the candidate lives, as entered. | Austin, TX |
data[].details.linkedin_url |
string |
Optional | Yes | Sensitive | LinkedIn profile link. | https://www.linkedin.com/in/example |
data[].details.portfolio_url |
string |
Optional | Yes | Sensitive | Portfolio or personal site link. | null |
data[].details.summary |
string |
Optional | Yes | Sensitive | Professional summary. | Five years on the line. |
data[].details.availability |
string |
Optional | Yes | Sensitive | Start date or availability. | Two weeks |
data[].details.us_work_authorized |
boolean |
Optional | Yes | Sensitive | Answer to the US work authorization question, or null. | true |
data[].details.requires_visa_sponsorship |
boolean |
Optional | Yes | Sensitive | Answer to the visa sponsorship question, or null. | false |
data[].details.salary_expectation |
string |
Optional | Yes | Sensitive | Desired pay, as entered. | $20/hr |
data[].details.cover_letter |
string |
Optional | Yes | Sensitive | Cover letter text. | null |
data[].details.screening_answers |
array<object> |
Optional | No | Sensitive | Answers to the job's screening questions: key, prompt, type and answer. | [{"key":"q1","prompt":"Can you work weekends?","type":"YES_NO","answer":"Yes"}] |
data[].details.resume |
object |
Optional | Yes | Sensitive | The uploaded resume's file_name, mime_type and size_bytes, or null. The file itself is never returned. | {"file_name":"resume.pdf","mime_type":"application/pdf","size_bytes":48211} |
data[].details.rating |
integer |
Optional | Yes | Sensitive | The team's 1 to 5 star rating, or null. | 4 |
data[].details.decline_reason |
string |
Optional | Yes | Sensitive | Why the candidate was not selected, while DECLINED. | null |
data[].details.decline_reason_label |
string |
Optional | Yes | Sensitive | Wording of the not-selected reason. | null |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.row_count |
integer |
Required | No | Standard | Rows in this page. | 2 |
meta.limit |
integer |
Required | No | Standard | Page size used. | 100 |
meta.has_more |
boolean |
Required | No | Standard | Whether another page follows. | false |
meta.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id for the next page, or null. | null |
meta.includes_details |
boolean |
Required | No | Standard | Whether details are included (the token has applicants.sensitive:read). | false |
One applicant, as returned by the retrieve, add and update endpoints.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Applicant ID: one application, a person applying to one job. | 5012 |
data.candidate_id |
integer |
Required | No | Standard | The person. One candidate can apply to several jobs. | 3307 |
data.job_id |
integer |
Required | No | Standard | Job the application is for. | 18 |
data.job_title |
string |
Required | No | Standard | Job title. | Line Cook |
data.first_name |
string |
Required | No | Standard | First name. | Pat |
data.last_name |
string |
Required | No | Standard | Last name. | Lee |
data.email |
string |
Required | No | Standard | Email address, lowercase. | pat.lee@example.com |
data.phone |
string |
Required | Yes | Standard | Phone number as entered. | 555-123-4567 |
data.stage |
enum |
Required | No | Standard | NEW, REVIEW, SCREEN, INTERVIEW, OFFER, HIRED, DECLINED or WITHDRAWN. | INTERVIEW |
data.stage_label |
string |
Required | No | Standard | The company's own name for the stage. | Interview |
data.source |
string |
Required | No | Standard | Where the application came from. | Indeed |
data.employee_id |
integer |
Required | Yes | Standard | Employee created when the candidate was hired, or null. | null |
data.applied_at |
date-time |
Required | No | Standard | When the application arrived. | 2026-10-14 09:12:00 |
data.updated_at |
date-time |
Required | No | Standard | Last change to the application. | 2026-10-15 16:40:00 |
data.stage_history |
array<object> |
Required | No | Standard | Stage moves, oldest first: stage and changed_at; with applicants.sensitive:read also changed_by and notes. | [{"stage":"NEW","changed_at":"2026-10-14 09:12:00"}] |
data.interviews |
array<object> |
Required | No | Standard | Interview invitations: id, status (OPEN, BOOKED, CANCELLED or EXPIRED), location_type, starts_at_utc and ends_at_utc. | [] |
data.details |
object |
Optional | No | Sensitive | Present only with applicants.sensitive:read. | {...} |
data.details.location |
string |
Optional | Yes | Sensitive | Where the candidate lives, as entered. | Austin, TX |
data.details.linkedin_url |
string |
Optional | Yes | Sensitive | LinkedIn profile link. | https://www.linkedin.com/in/example |
data.details.portfolio_url |
string |
Optional | Yes | Sensitive | Portfolio or personal site link. | null |
data.details.summary |
string |
Optional | Yes | Sensitive | Professional summary. | Five years on the line. |
data.details.availability |
string |
Optional | Yes | Sensitive | Start date or availability. | Two weeks |
data.details.us_work_authorized |
boolean |
Optional | Yes | Sensitive | Answer to the US work authorization question, or null. | true |
data.details.requires_visa_sponsorship |
boolean |
Optional | Yes | Sensitive | Answer to the visa sponsorship question, or null. | false |
data.details.salary_expectation |
string |
Optional | Yes | Sensitive | Desired pay, as entered. | $20/hr |
data.details.cover_letter |
string |
Optional | Yes | Sensitive | Cover letter text. | null |
data.details.screening_answers |
array<object> |
Optional | No | Sensitive | Answers to the job's screening questions: key, prompt, type and answer. | [{"key":"q1","prompt":"Can you work weekends?","type":"YES_NO","answer":"Yes"}] |
data.details.resume |
object |
Optional | Yes | Sensitive | The uploaded resume's file_name, mime_type and size_bytes, or null. The file itself is never returned. | {"file_name":"resume.pdf","mime_type":"application/pdf","size_bytes":48211} |
data.details.rating |
integer |
Optional | Yes | Sensitive | The team's 1 to 5 star rating, or null. | 4 |
data.details.decline_reason |
string |
Optional | Yes | Sensitive | Why the candidate was not selected, while DECLINED. | null |
data.details.decline_reason_label |
string |
Optional | Yes | Sensitive | Wording of the not-selected reason. | null |
data.details.notes |
array<object> |
Optional | No | Sensitive | The team's notes, newest first: id, author_name, body and created_at. | [] |
meta.request_id |
string |
Required | No | Standard | Request correlation ID. | req_xxx |
meta.includes_details |
boolean |
Required | No | Standard | Whether details are included. | false |
meta.new_candidate |
boolean |
Optional | No | Conditional | Add only: false when the email had applied to another job before. | true |
meta.ignored_fields |
array<string> |
Optional | No | Conditional | Add only: fields that were checked but not kept (resume_url). | ["resume_url"] |
meta.changed |
boolean |
Optional | No | Conditional | Update only: whether the stage changed. | true |
meta.note_added |
boolean |
Optional | No | Conditional | Update only: whether a note was added. | true |
meta.previous_stage |
enum |
Optional | No | Conditional | Update only: the stage before this request. | INTERVIEW |
JSON body for POST /api/v1/applicants. Any other field answers 422 unknown_field.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
job_id |
integer |
Required | No | Standard | An OPEN job of this company. | 18 |
first_name |
string |
Required | No | Standard | Up to 80 characters. | Pat |
last_name |
string |
Required | No | Standard | Up to 80 characters. | Lee |
email |
string |
Required | No | Standard | A valid email; one application per email per job. | pat.lee@example.com |
phone |
string |
Required | No | Standard | Up to 40 characters. | 555-123-4567 |
source |
string |
Optional | Yes | Standard | Where the application came from, up to 120 characters. Defaults to the API client's name. | Indeed |
resume_url |
string |
Optional | Yes | Standard | An http or https link. Checked, not kept, and never fetched. | https://jobs.example.com/resume/123 |
JSON body for PATCH /api/v1/applicants/{applicant_id}. Send a stage, a note, or both.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
stage |
enum |
Optional | No | Standard | NEW, REVIEW, SCREEN, INTERVIEW, OFFER, DECLINED or WITHDRAWN. HIRED only for a candidate who already has an employee record. | INTERVIEW |
decline_reason |
enum |
Optional | Yes | Standard | With stage DECLINED: SCHEDULE, EXPERIENCE, REQUIREMENTS, PAY, NO_RESPONSE, OTHER_CANDIDATE, JOB_CLOSED, DUPLICATE or OTHER. | SCHEDULE |
note |
string |
Optional | Yes | Sensitive | A note for the hiring team, up to 10,000 characters. Signed "API: <client name>". | Phone screen went well. |
expected_updated_at |
date-time |
Optional | Yes | Standard | The updated_at you read. A different value answers 409 applicant_changed. | 2026-10-15 16:40:00 |
Payload for recruiting.applicant.created. Only the basic applicant record: never screening answers, resumes, notes or EEO answers.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
applicant.id |
integer |
Required | No | Standard | Applicant ID: one application, a person applying to one job. | 5012 |
applicant.candidate_id |
integer |
Required | No | Standard | The person. One candidate can apply to several jobs. | 3307 |
applicant.job_id |
integer |
Required | No | Standard | Job the application is for. | 18 |
applicant.job_title |
string |
Required | No | Standard | Job title. | Line Cook |
applicant.first_name |
string |
Required | No | Standard | First name. | Pat |
applicant.last_name |
string |
Required | No | Standard | Last name. | Lee |
applicant.email |
string |
Required | No | Standard | Email address, lowercase. | pat.lee@example.com |
applicant.phone |
string |
Required | Yes | Standard | Phone number as entered. | 555-123-4567 |
applicant.stage |
enum |
Required | No | Standard | NEW, REVIEW, SCREEN, INTERVIEW, OFFER, HIRED, DECLINED or WITHDRAWN. | INTERVIEW |
applicant.stage_label |
string |
Required | No | Standard | The company's own name for the stage. | Interview |
applicant.source |
string |
Required | No | Standard | Where the application came from. | Indeed |
applicant.employee_id |
integer |
Required | Yes | Standard | Employee created when the candidate was hired, or null. | null |
applicant.applied_at |
date-time |
Required | No | Standard | When the application arrived. | 2026-10-14 09:12:00 |
applicant.updated_at |
date-time |
Required | No | Standard | Last change to the application. | 2026-10-15 16:40:00 |
channel |
enum |
Required | No | Standard | CAREERS_SITE or API. | API |
api_client |
string |
Required | Yes | Standard | The API client that added the applicant, or null. | Indeed connector |
Payload for recruiting.applicant.stage_changed and recruiting.applicant.hired.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
applicant.id |
integer |
Required | No | Standard | Applicant ID: one application, a person applying to one job. | 5012 |
applicant.candidate_id |
integer |
Required | No | Standard | The person. One candidate can apply to several jobs. | 3307 |
applicant.job_id |
integer |
Required | No | Standard | Job the application is for. | 18 |
applicant.job_title |
string |
Required | No | Standard | Job title. | Line Cook |
applicant.first_name |
string |
Required | No | Standard | First name. | Pat |
applicant.last_name |
string |
Required | No | Standard | Last name. | Lee |
applicant.email |
string |
Required | No | Standard | Email address, lowercase. | pat.lee@example.com |
applicant.phone |
string |
Required | Yes | Standard | Phone number as entered. | 555-123-4567 |
applicant.stage |
enum |
Required | No | Standard | NEW, REVIEW, SCREEN, INTERVIEW, OFFER, HIRED, DECLINED or WITHDRAWN. | INTERVIEW |
applicant.stage_label |
string |
Required | No | Standard | The company's own name for the stage. | Interview |
applicant.source |
string |
Required | No | Standard | Where the application came from. | Indeed |
applicant.employee_id |
integer |
Required | Yes | Standard | Employee created when the candidate was hired, or null. | null |
applicant.applied_at |
date-time |
Required | No | Standard | When the application arrived. | 2026-10-14 09:12:00 |
applicant.updated_at |
date-time |
Required | No | Standard | Last change to the application. | 2026-10-15 16:40:00 |
previous_stage |
enum |
Required | No | Standard | Stage before the move. | OFFER |
stage |
enum |
Required | No | Standard | Stage after the move. | HIRED |
changed_at |
date-time |
Required | No | Standard | ISO 8601 time of the move. | 2026-10-16T10:05:00-05:00 |
changed_by.type |
enum |
Required | No | Standard | USER or API_CLIENT. | USER |
changed_by.name |
string |
Required | Yes | Standard | Name of the person or API client. | Jordan Lee |
Query parameters for GET /api/v1/announcements.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
published_from |
date |
Optional | No | Standard | Only announcements published on or after this day (company calendar). | 2026-10-01 |
published_to |
date |
Optional | No | Standard | Only announcements published on or before this day (company calendar). | 2026-10-31 |
limit |
integer |
Optional | No | Standard | Page size, 1-500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Cursor: meta.next_after_id from the previous page. | 318 |
A page of announcements.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Announcement ID. | 318 |
data[].title |
string |
Required | No | Standard | Title (may be empty when the announcement has only a body). | Holiday hours |
data[].body |
string |
Required | No | Standard | The message as plain text: paragraphs separated by a blank line, list items as "- " lines. | The store closes at 3 PM on Friday. |
data[].priority |
enum |
Required | No | Standard | NORMAL, HIGH or URGENT. | HIGH |
data[].audience.type |
enum |
Required | No | Standard | everyone, or department for one department. | department |
data[].audience.department_id |
integer |
Optional | No | Standard | The department, when audience.type is department. | 4 |
data[].audience.department_name |
string |
Optional | Yes | Standard | The department name, when audience.type is department. | Kitchen |
data[].status |
enum |
Required | No | Standard | scheduled (publish time still ahead), active, or expired. | active |
data[].published_at |
date-time |
Required | No | Standard | When employees see it, on the company clock (meta.timezone). | 2026-10-16 09:00:00 |
data[].expires_at |
date-time |
Required | Yes | Standard | When it stops showing, on the company clock; null when it never expires. | 2026-10-24 23:59:59 |
data[].author |
object |
Required | Yes | Standard | The AppyShift user who posted it ({"user_id","name"}); null when it was posted through the API. | {"user_id":7,"name":"Pat Morgan"} |
data[].requires_acknowledgement |
boolean |
Required | No | Standard | Whether employees must acknowledge it. | true |
data[].acknowledged_count |
integer |
Required | Yes | Standard | Active employees it is for who acknowledged it; null when acknowledgement is not required. | 14 |
data[].audience_count |
integer |
Required | Yes | Standard | Active employees it is for today. | 22 |
data[].read_count |
integer |
Required | Yes | Standard | Active employees it is for who opened it; null when read tracking is not installed. | 19 |
data[].created_at |
date-time |
Required | No | Standard | When it was saved. | 2026-10-15 16:42:10 |
meta.timezone |
string |
Required | No | Standard | The company time zone the times are in. | America/Chicago |
meta.row_count |
integer |
Required | No | Standard | Rows in this page. | 1 |
meta.limit |
integer |
Required | No | Standard | Page size used. | 100 |
meta.has_more |
boolean |
Required | No | Standard | Whether another page follows. | false |
meta.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id for the next page; null on the last page. | null |
One announcement.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Announcement ID. | 318 |
data.title |
string |
Required | No | Standard | Title (may be empty when the announcement has only a body). | Holiday hours |
data.body |
string |
Required | No | Standard | The message as plain text: paragraphs separated by a blank line, list items as "- " lines. | The store closes at 3 PM on Friday. |
data.priority |
enum |
Required | No | Standard | NORMAL, HIGH or URGENT. | HIGH |
data.audience.type |
enum |
Required | No | Standard | everyone, or department for one department. | department |
data.audience.department_id |
integer |
Optional | No | Standard | The department, when audience.type is department. | 4 |
data.audience.department_name |
string |
Optional | Yes | Standard | The department name, when audience.type is department. | Kitchen |
data.status |
enum |
Required | No | Standard | scheduled (publish time still ahead), active, or expired. | active |
data.published_at |
date-time |
Required | No | Standard | When employees see it, on the company clock (meta.timezone). | 2026-10-16 09:00:00 |
data.expires_at |
date-time |
Required | Yes | Standard | When it stops showing, on the company clock; null when it never expires. | 2026-10-24 23:59:59 |
data.author |
object |
Required | Yes | Standard | The AppyShift user who posted it ({"user_id","name"}); null when it was posted through the API. | {"user_id":7,"name":"Pat Morgan"} |
data.requires_acknowledgement |
boolean |
Required | No | Standard | Whether employees must acknowledge it. | true |
data.acknowledged_count |
integer |
Required | Yes | Standard | Active employees it is for who acknowledged it; null when acknowledgement is not required. | 14 |
data.audience_count |
integer |
Required | Yes | Standard | Active employees it is for today. | 22 |
data.read_count |
integer |
Required | Yes | Standard | Active employees it is for who opened it; null when read tracking is not installed. | 19 |
data.created_at |
date-time |
Required | No | Standard | When it was saved. | 2026-10-15 16:42:10 |
meta.timezone |
string |
Required | No | Standard | The company time zone the times are in. | America/Chicago |
JSON body for POST /api/v1/announcements. Any other field answers 422 unknown_field.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
title |
string |
Optional | No | Standard | Up to 200 characters. A title or a body is required. | Inventory count Sunday |
body |
string |
Optional | No | Standard | Plain text, up to 20,000 characters. A blank line starts a new paragraph. | Please plan to stay 30 minutes after close. |
priority |
enum |
Optional | No | Standard | NORMAL (default), HIGH or URGENT. | NORMAL |
audience |
string|object |
Optional | No | Standard | "everyone" (default) or {"type":"department","department_id":12} for one department of this company. | {"type":"department","department_id":4} |
publish_at |
date|date-time |
Optional | No | Standard | When employees see it (default now). A date means the start of that day. Read on the company clock unless it carries an offset. | 2026-10-17T08:00:00 |
expires_at |
date|date-time |
Optional | No | Standard | When it stops showing. A date means the end of that day. Must be in the future and after publish_at. | 2026-10-20 |
require_acknowledgement |
boolean |
Optional | No | Standard | Employees must acknowledge it (default false). | true |
deliver |
array<enum> |
Optional | No | Standard | Also send it by push notification and/or email to everyone it is for, at the publish time: push, email. | ["push","email"] |
The posted announcement (HTTP 201) and how it will be sent.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Announcement ID. | 318 |
data.title |
string |
Required | No | Standard | Title (may be empty when the announcement has only a body). | Holiday hours |
data.body |
string |
Required | No | Standard | The message as plain text: paragraphs separated by a blank line, list items as "- " lines. | The store closes at 3 PM on Friday. |
data.priority |
enum |
Required | No | Standard | NORMAL, HIGH or URGENT. | HIGH |
data.audience.type |
enum |
Required | No | Standard | everyone, or department for one department. | department |
data.audience.department_id |
integer |
Optional | No | Standard | The department, when audience.type is department. | 4 |
data.audience.department_name |
string |
Optional | Yes | Standard | The department name, when audience.type is department. | Kitchen |
data.status |
enum |
Required | No | Standard | scheduled (publish time still ahead), active, or expired. | active |
data.published_at |
date-time |
Required | No | Standard | When employees see it, on the company clock (meta.timezone). | 2026-10-16 09:00:00 |
data.expires_at |
date-time |
Required | Yes | Standard | When it stops showing, on the company clock; null when it never expires. | 2026-10-24 23:59:59 |
data.author |
object |
Required | Yes | Standard | The AppyShift user who posted it ({"user_id","name"}); null when it was posted through the API. | {"user_id":7,"name":"Pat Morgan"} |
data.requires_acknowledgement |
boolean |
Required | No | Standard | Whether employees must acknowledge it. | true |
data.acknowledged_count |
integer |
Required | Yes | Standard | Active employees it is for who acknowledged it; null when acknowledgement is not required. | 14 |
data.audience_count |
integer |
Required | Yes | Standard | Active employees it is for today. | 22 |
data.read_count |
integer |
Required | Yes | Standard | Active employees it is for who opened it; null when read tracking is not installed. | 19 |
data.created_at |
date-time |
Required | No | Standard | When it was saved. | 2026-10-15 16:42:10 |
meta.timezone |
string |
Required | No | Standard | The company time zone the times are in. | America/Chicago |
meta.delivery.requested |
array<string> |
Required | No | Standard | Channels asked for in deliver. | ["push","email"] |
meta.delivery.queued |
array<string> |
Required | No | Standard | Channels queued to send at the publish time. | ["push","email"] |
meta.delivery.message |
string |
Required | Yes | Standard | Why requested channels were not queued (for example, pending migrations). | null |
Query parameters for GET /api/v1/surveys.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
active |
boolean |
Optional | No | Standard | true for open surveys only, false for closed ones only. | true |
limit |
integer |
Optional | No | Standard | Page size, 1-500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Cursor: meta.next_after_id from the previous page. | 12 |
A page of surveys with participation counts.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data[].id |
integer |
Required | No | Standard | Survey ID. | 12 |
data[].title |
string |
Required | No | Standard | Survey title. | Quarterly pulse |
data[].description |
string |
Required | Yes | Standard | Survey description. | Five quick questions about your work week. |
data[].active |
boolean |
Required | No | Standard | Whether employees can still answer it. | true |
data[].question_count |
integer |
Required | No | Standard | Questions in the survey. | 5 |
data[].assigned_count |
integer |
Required | No | Standard | Employees it was assigned to. | 40 |
data[].completed_count |
integer |
Required | No | Standard | Employees who submitted it. | 31 |
data[].response_rate |
integer |
Required | No | Standard | completed_count as a percent of assigned_count. | 78 |
data[].created_at |
date-time |
Required | Yes | Standard | When it was created. | 2026-10-01 08:30:00 |
meta.row_count |
integer |
Required | No | Standard | Rows in this page. | 1 |
meta.limit |
integer |
Required | No | Standard | Page size used. | 100 |
meta.has_more |
boolean |
Required | No | Standard | Whether another page follows. | false |
meta.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id for the next page; null on the last page. | null |
A survey's results as counts only. Never who answered, one person's answers, or written answers.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data.id |
integer |
Required | No | Standard | Survey ID. | 12 |
data.title |
string |
Required | No | Standard | Survey title. | Quarterly pulse |
data.description |
string |
Required | Yes | Standard | Survey description. | null |
data.active |
boolean |
Required | No | Standard | Whether employees can still answer it. | true |
data.assigned_count |
integer |
Required | No | Standard | Employees it was assigned to. | 40 |
data.completed_count |
integer |
Required | No | Standard | Employees who submitted it. | 31 |
data.response_rate |
integer |
Required | No | Standard | completed_count as a percent of assigned_count. | 78 |
data.questions[].id |
integer |
Required | No | Standard | Question ID. | 51 |
data.questions[].text |
string |
Required | No | Standard | The question. | Which shift do you prefer? |
data.questions[].type |
enum |
Required | No | Standard | multiple_choice, rating, yes_no or text. | multiple_choice |
data.questions[].required |
boolean |
Required | No | Standard | Whether an answer was required. | true |
data.questions[].response_count |
integer |
Required | No | Standard | Completed responses that answered this question. | 31 |
data.questions[].options[] |
array<object> |
Optional | No | Standard | multiple_choice only: {"id","text","count"} per choice; id is null for "Removed option". | [{"id":140,"text":"Morning","count":18}] |
data.questions[].rating |
object |
Optional | No | Standard | rating only: {"average" (1 decimal, null with no answers), "distribution" ("1" to "5" => count)}. | {"average":4.2,"distribution":{"1":0,"2":1,"3":4,"4":12,"5":13}} |
data.questions[].yes_no |
object |
Optional | No | Standard | yes_no only: {"yes","no"} counts. | {"yes":27,"no":4} |
meta.aggregate_only |
boolean |
Required | No | Standard | Always true: the API returns no individual answers. | true |
Payload produced when an announcement is posted on the Announcements page or through the API.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
announcement |
object |
Required | No | Standard | The announcement, with the same fields as AnnouncementResponse.data except the acknowledgement and read counts. | {"id":319,"title":"Inventory count Sunday",...} |
announcement.status |
enum |
Required | No | Standard | scheduled when publish_at is still ahead (employees see it then), otherwise active. | scheduled |
actor |
object |
Required | No | Standard | Who posted it: {"type":"USER","id":7,"name":"Pat Morgan"} or {"type":"API_CLIENT","id":3,"name":"HR sync"}. | {"type":"API_CLIENT","id":3,"name":"HR sync"} |
posted_at |
date-time |
Required | No | Standard | ISO 8601 time it was posted. | 2026-10-16T10:12:44-05:00 |
Payload produced when an employee completes all onboarding tasks currently available to them. Task titles, form answers, signatures, documents, and tax or identity data are excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee.id |
integer |
Required | No | Standard | Employee ID. | 42 |
employee.display_name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
employee.manager_id |
integer |
Required | Yes | Standard | Assigned manager employee ID. | 9 |
employee.hire_date |
date |
Required | No | Standard | Employee hire date, or an empty string. | 2026-08-24 |
completion.completed_task_id |
integer |
Required | No | Standard | Task whose completion closed the currently available checklist. | 812 |
completion.available_task_count |
integer |
Required | No | Standard | Currently unlocked onboarding tasks. | 7 |
completion.completed_task_count |
integer |
Required | No | Standard | Completed currently unlocked tasks. | 7 |
completion.completed_at |
date-time |
Required | No | Standard | ISO 8601 checklist completion timestamp. | 2026-08-20T11:15:00-05:00 |
actor.type |
enum |
Required | No | Standard | EMPLOYEE or USER. | EMPLOYEE |
actor.id |
integer |
Required | Yes | Standard | Employee or user ID that completed the final task. | 42 |
One new hire's onboarding, as listed by GET /api/v1/onboarding. Form answers, signature images, IP addresses, Social Security numbers, I-9 document numbers or images, bank details and uploaded files are never included.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
name |
string |
Required | No | Standard | Employee first and last name. | Jordan Lee |
employee_status |
enum |
Required | No | Standard | ACTIVE, INACTIVE, ON_LEAVE or TERMINATED. | ACTIVE |
start_date |
date |
Required | Yes | Standard | Hire date. | 2026-08-24 |
plan_name |
string |
Required | Yes | Standard | Name of the first onboarding plan assigned, or null when tasks were added one at a time. | Front desk onboarding |
plans |
array |
Required | No | Standard | Every onboarding plan the tasks came from, in the order assigned: id and name. | [{"id":3,"name":"Front desk onboarding"}] |
status |
enum |
Required | No | Standard | in_progress, or completed when every task is done (tasks that unlock later count). | in_progress |
started_at |
date-time |
Required | Yes | Standard | When the first onboarding task was assigned. | 2026-08-18 09:12:00 |
completed_at |
date-time |
Required | Yes | Standard | When the last task was finished; null while in progress. | 2026-08-29 16:40:00 |
progress.tasks.total |
integer |
Required | No | Standard | All onboarding tasks, forms included. | 7 |
progress.tasks.completed |
integer |
Required | No | Standard | Finished tasks. | 5 |
progress.tasks.overdue |
integer |
Required | No | Standard | Unfinished, unlocked tasks past their due date. | 1 |
progress.forms.total |
integer |
Required | No | Standard | Tasks that are forms: PDF forms, the Form I-9 and other guided forms. | 3 |
progress.forms.completed |
integer |
Required | No | Standard | Finished forms. | 2 |
i9.status |
enum |
Required | No | Standard | not_assigned, awaiting_section_1, awaiting_section_2 or complete. | awaiting_section_2 |
i9.section_1_complete |
boolean |
Required | No | Standard | The employee finished and signed Section 1. | true |
i9.section_1_completed_at |
date-time |
Required | Yes | Standard | When Section 1 was finished. | 2026-08-19 10:02:11 |
i9.section_2_complete |
boolean |
Required | No | Standard | The employer finished and signed Section 2. | false |
i9.section_2_completed_at |
date-time |
Required | Yes | Standard | When Section 2 was finished. | null |
i9.correction_requested |
boolean |
Required | No | Standard | A Section 1 correction was asked for and not made yet. | false |
e_signatures.status |
enum |
Required | No | Standard | not_required, pending or complete, across PDF forms and the Form I-9. | pending |
e_signatures.required |
integer |
Required | No | Standard | Signatures needed (employee and manager). | 4 |
e_signatures.signed |
integer |
Required | No | Standard | Signatures collected. | 3 |
e_signatures.awaiting_employee |
integer |
Required | No | Standard | Employee signatures still needed. | 0 |
e_signatures.awaiting_manager |
integer |
Required | No | Standard | Manager signatures needed on forms the employee has sent. | 1 |
e_signatures.last_signed_at |
date-time |
Required | Yes | Standard | The most recent signature. | 2026-08-19 10:02:11 |
Every OnboardingHire field plus each task and form. Titles, statuses and dates only. Form answers, signature images, IP addresses, Social Security numbers, I-9 document numbers or images, bank details and uploaded files are never included.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee_id |
integer |
Required | No | Standard | Employee ID. | 42 |
name |
string |
Required | No | Standard | Employee first and last name. | Jordan Lee |
employee_status |
enum |
Required | No | Standard | ACTIVE, INACTIVE, ON_LEAVE or TERMINATED. | ACTIVE |
start_date |
date |
Required | Yes | Standard | Hire date. | 2026-08-24 |
plan_name |
string |
Required | Yes | Standard | Name of the first onboarding plan assigned, or null when tasks were added one at a time. | Front desk onboarding |
plans |
array |
Required | No | Standard | Every onboarding plan the tasks came from, in the order assigned: id and name. | [{"id":3,"name":"Front desk onboarding"}] |
status |
enum |
Required | No | Standard | in_progress, or completed when every task is done (tasks that unlock later count). | in_progress |
started_at |
date-time |
Required | Yes | Standard | When the first onboarding task was assigned. | 2026-08-18 09:12:00 |
completed_at |
date-time |
Required | Yes | Standard | When the last task was finished; null while in progress. | 2026-08-29 16:40:00 |
progress.tasks.total |
integer |
Required | No | Standard | All onboarding tasks, forms included. | 7 |
progress.tasks.completed |
integer |
Required | No | Standard | Finished tasks. | 5 |
progress.tasks.overdue |
integer |
Required | No | Standard | Unfinished, unlocked tasks past their due date. | 1 |
progress.forms.total |
integer |
Required | No | Standard | Tasks that are forms: PDF forms, the Form I-9 and other guided forms. | 3 |
progress.forms.completed |
integer |
Required | No | Standard | Finished forms. | 2 |
i9.status |
enum |
Required | No | Standard | not_assigned, awaiting_section_1, awaiting_section_2 or complete. | awaiting_section_2 |
i9.section_1_complete |
boolean |
Required | No | Standard | The employee finished and signed Section 1. | true |
i9.section_1_completed_at |
date-time |
Required | Yes | Standard | When Section 1 was finished. | 2026-08-19 10:02:11 |
i9.section_2_complete |
boolean |
Required | No | Standard | The employer finished and signed Section 2. | false |
i9.section_2_completed_at |
date-time |
Required | Yes | Standard | When Section 2 was finished. | null |
i9.correction_requested |
boolean |
Required | No | Standard | A Section 1 correction was asked for and not made yet. | false |
e_signatures.status |
enum |
Required | No | Standard | not_required, pending or complete, across PDF forms and the Form I-9. | pending |
e_signatures.required |
integer |
Required | No | Standard | Signatures needed (employee and manager). | 4 |
e_signatures.signed |
integer |
Required | No | Standard | Signatures collected. | 3 |
e_signatures.awaiting_employee |
integer |
Required | No | Standard | Employee signatures still needed. | 0 |
e_signatures.awaiting_manager |
integer |
Required | No | Standard | Manager signatures needed on forms the employee has sent. | 1 |
e_signatures.last_signed_at |
date-time |
Required | Yes | Standard | The most recent signature. | 2026-08-19 10:02:11 |
tasks[].id |
integer |
Required | No | Standard | Onboarding task ID. | 812 |
tasks[].title |
string |
Required | No | Standard | Task title. Task content and instructions are not included. | Read the employee handbook |
tasks[].type |
enum |
Required | No | Standard | standard, acknowledgement, video_acknowledgement, manager_meeting, custom_form, i9, knowledge_check or credential_upload. | acknowledgement |
tasks[].type_label |
string |
Required | No | Standard | The type as AppyShift shows it. | Guided Step |
tasks[].plan_id |
integer |
Required | Yes | Standard | Plan the task came from; null for a task added by hand. | 3 |
tasks[].status |
enum |
Required | No | Standard | completed, open, overdue, or locked (unlocks on a later date). | open |
tasks[].due_date |
date |
Required | Yes | Standard | Due date. | 2026-08-30 |
tasks[].unlocks_on |
date |
Required | Yes | Standard | Date the task unlocks, when it unlocks after the hire date. | null |
tasks[].completed_at |
date-time |
Required | Yes | Standard | When the task was finished. | null |
tasks[].is_form |
boolean |
Required | No | Standard | The task is a form. | true |
tasks[].form.kind |
enum |
Required | Yes | Standard | pdf, i9 or other; form is null when is_form is false. | pdf |
tasks[].form.submitted_at |
date-time |
Required | Yes | Standard | When the employee sent the form (Section 1 for the Form I-9). | 2026-08-19 10:02:11 |
tasks[].form.employee_signature |
enum |
Required | Yes | Standard | not_required, pending or signed; null for kind other. | signed |
tasks[].form.employee_signed_at |
date-time |
Required | Yes | Standard | When the employee signed. | 2026-08-19 10:02:11 |
tasks[].form.manager_signature |
enum |
Required | Yes | Standard | not_required, pending or signed; null for kind other. | pending |
tasks[].form.manager_signed_at |
date-time |
Required | Yes | Standard | When the manager or employer signed. | null |
Payload produced when an onboarding plan is assigned to an employee who had no onboarding tasks yet. Task titles and content, form answers, signatures, documents, and tax or identity data are excluded.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee.id |
integer |
Required | No | Standard | Employee ID. | 42 |
employee.display_name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
employee.manager_id |
integer |
Required | Yes | Standard | Assigned manager ID. | 9 |
employee.hire_date |
date |
Required | No | Standard | Employee hire date, or an empty string. | 2026-08-24 |
onboarding.plan_id |
integer |
Required | No | Standard | Onboarding plan (template) assigned. | 3 |
onboarding.plan_name |
string |
Required | No | Standard | Plan name. | Front desk onboarding |
onboarding.task_count |
integer |
Required | No | Standard | Onboarding tasks assigned, including ones that unlock later. | 7 |
onboarding.started_at |
date-time |
Required | No | Standard | ISO 8601 timestamp of the assignment. | 2026-08-18T09:12:00-05:00 |
actor.type |
enum |
Required | No | Standard | USER, or SYSTEM when no signed-in person assigned it. | USER |
actor.id |
integer |
Required | Yes | Standard | User ID that assigned the plan. | 7 |
Payload of training.assigned, training.completed and training.certification_recorded (Pro plan). It names the employee, the course or quick quiz and the assignment dates. Lesson content, quiz questions and answers, scores and signatures are never included. training.assigned adds assigned_by; training.certification_recorded adds certification.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
employee.id |
integer |
Required | No | Standard | Employee ID. | 42 |
employee.display_name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
employee.payroll_id |
string |
Required | Yes | Standard | The employee's Payroll ID, when one is set. | E1042 |
course.id |
integer |
Required | No | Standard | Course or quick quiz ID. | 27 |
course.title |
string |
Required | No | Standard | Course or quick quiz title. | Food safety basics |
course.version |
integer |
Required | No | Standard | The published version the employee was given. | 3 |
assignment.id |
integer |
Required | No | Standard | Assignment ID. | 318 |
assignment.status |
enum |
Required | No | Standard | ASSIGNED, IN_PROGRESS, AWAITING_REVIEW, PASSED, FAILED, WAIVED or CANCELED. | PASSED |
assignment.due_date |
date |
Required | Yes | Standard | Due date on the company calendar. | 2026-11-06 |
assignment.assigned_at |
date-time |
Required | No | Standard | When it was assigned. | 2026-10-23 14:05:00 |
assignment.cycle |
integer |
Required | No | Standard | Renewal cycle, 1 for the first time. | 1 |
assignment.passed_on |
date |
Required | Yes | Standard | The day it was passed, on the company calendar. | 2026-10-24 |
assignment.expires_on |
date |
Required | Yes | Standard | When a renewing course expires. | 2027-10-24 |
assignment.completed_how |
enum |
Required | Yes | Standard | in_app, recorded (taken elsewhere, entered by staff) or imported (from a spreadsheet); null until passed. | in_app |
assignment.started_by_employee |
boolean |
Required | No | Standard | The employee started an open course themselves. | false |
assigned_by |
enum |
Optional | No | Standard | training.assigned only: how it was assigned (staff, rule, learning_path, renewal, onboarding or employee). | onboarding |
certification |
object |
Optional | No | Standard | training.certification_recorded only: the certification (id, name, issued_at, expires_at). | {"id":88,"name":"Food handler","issued_at":"2026-10-24","expires_at":null} |
Date range, filters and paging for home care visits.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
date_from |
date |
Required | No | Standard | First visit date included, YYYY-MM-DD. | 2026-10-01 |
date_to |
date |
Required | No | Standard | Last visit date included; the range covers at most 62 days. | 2026-10-14 |
employee_id |
integer |
Optional | No | Standard | Only visits this caregiver is assigned to or recorded time on. Another company's employee answers 404. | 42 |
status |
string |
Optional | No | Standard | One or more of scheduled, in_progress, completed, missed, cancelled, separated by commas. | completed,missed |
limit |
integer |
Optional | No | Standard | Visits per page, 1 to 500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Return visits after this visit ID: meta.next_after_id from the previous page. | 9101 |
Home care visits in visit ID order. No client details: the label is always "Home visit" and the client is an opaque reference.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
data |
array<HomeCareVisit> |
Required | No | Standard | Visits in the range, ordered by visit ID. | [{...}] |
data[].id |
integer |
Required | No | Standard | Visit ID (the schedule shift ID). | 9101 |
data[].label |
string |
Required | No | Standard | Always "Home visit". Client names and addresses never leave AppyShift. | Home visit |
data[].client_ref |
string |
Required | No | Standard | Opaque, stable reference for the visit's client within this company, for grouping visits. Not derived from any client detail and different in every company. | hc_5f0c2a9e41b7d3386a1e2c4f |
data[].visit_date |
date |
Required | No | Standard | Scheduled visit date. | 2026-10-05 |
data[].status |
enum |
Required | No | Standard | scheduled, in_progress (clocked in), completed (time recorded), missed (ended with nobody clocked in) or cancelled. | completed |
data[].employee |
object |
Required | Yes | Standard | The caregiver who recorded time on the visit, else the one assigned; null for an open visit nobody worked. | {...} |
data[].employee.id |
integer |
Required | No | Standard | Employee ID. | 42 |
data[].employee.name |
string |
Required | No | Standard | Employee display name. | Jordan Lee |
data[].employee.payroll_id |
string |
Required | No | Conditional | External payroll identifier, or an empty string. | EE-1042 |
data[].scheduled_start |
date-time |
Required | No | Standard | Scheduled start, ISO 8601 with the company's UTC offset. | 2026-10-05T09:00:00-05:00 |
data[].scheduled_end |
date-time |
Required | No | Standard | Scheduled end; the next day for a visit past midnight. | 2026-10-05T11:00:00-05:00 |
data[].scheduled_minutes |
integer |
Required | No | Standard | Scheduled length in minutes. | 120 |
data[].clock_in |
object |
Required | Yes | Standard | First clock-in on the visit, or null when nobody clocked in. | {...} |
data[].clock_in.at |
date-time |
Required | No | Standard | Clock-in time, ISO 8601 with the company's UTC offset. | 2026-10-05T09:04:00-05:00 |
data[].clock_in.method |
enum |
Required | No | Standard | time_clock or by_hand (entered or added by a manager). | time_clock |
data[].clock_in.location_check |
enum |
Required | Yes | Standard | The time clock's check against the visit location: at_visit, away_from_visit or not_checked; null for times entered by hand. GPS positions are never returned. | at_visit |
data[].clock_out |
object |
Required | Yes | Standard | Last clock-out on the visit (same fields as clock_in), or null while under way or not worked. | {...} |
data[].worked_minutes |
integer |
Required | No | Standard | Minutes recorded on the visit after breaks; 0 until time is recorded. | 118 |
data[].worked_hours |
number |
Required | No | Standard | worked_minutes in hours, rounded to two decimals. | 1.97 |
data[].time_status |
enum |
Required | Yes | Standard | approved when every time entry is approved, pending otherwise; null with no time recorded. | approved |
data[].mileage |
object |
Required | Yes | Standard | Travel from the caregiver's previous visit that day, when tracked; null otherwise. | {...} |
data[].mileage.miles |
number |
Required | No | Standard | Estimated driving miles. | 4.2 |
data[].mileage.travel_minutes |
integer |
Required | No | Standard | Paid travel minutes. | 12 |
data[].mileage.amount |
number |
Required | No | Standard | Mileage reimbursement amount. | 2.94 |
data[].mileage.status |
enum |
Required | No | Standard | pending, approved or rejected (manager review in Travel & visit pay). | approved |
meta.date_from |
date |
Required | No | Standard | Applied range start. | 2026-10-01 |
meta.date_to |
date |
Required | No | Standard | Applied range end. | 2026-10-14 |
meta.timezone |
string |
Required | No | Standard | The company time zone the times are in. | America/Chicago |
meta.row_count |
integer |
Required | No | Standard | Visits returned. | 1 |
meta.limit |
integer |
Required | No | Standard | Applied page size. | 100 |
meta.has_more |
boolean |
Required | No | Standard | Whether another page follows. | false |
meta.next_after_id |
integer |
Required | Yes | Standard | Pass as after_id for the next page; null on the last page. | null |
Query parameters for listing work orders. All are optional.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
status |
string |
Optional | No | Standard | REQUESTED, OPEN, IN_PROGRESS, COMPLETED or CANCELED; several separated by commas. | OPEN,IN_PROGRESS |
location_id |
integer |
Optional | No | Standard | Only this work location. | 3 |
site_id |
integer |
Optional | No | Standard | Only this customer site (when customer sites are on). | 18 |
assigned_employee_id |
integer |
Optional | No | Standard | Only work orders assigned to this employee. | 42 |
from |
date |
Optional | No | Standard | Work order date on or after. | 2026-10-01 |
to |
date |
Optional | No | Standard | Work order date on or before. | 2026-10-31 |
updated_since |
date-time |
Optional | No | Standard | Changed at or after this ISO 8601 date or timestamp. | 2026-10-15T00:00:00Z |
limit |
integer |
Optional | No | Standard | Page size from 1 to 500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Cursor: the meta.next_after_id of the previous page. | 1041 |
Query parameters shared by the checklist, incident and tip declaration lists. Without from, to or updated_since, the last 30 days are returned.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
from |
date |
Optional | No | Standard | On or after this date (checklist date, incident date or work date). | 2026-10-01 |
to |
date |
Optional | No | Standard | On or before this date. | 2026-10-16 |
updated_since |
date-time |
Optional | No | Standard | Changed at or after this ISO 8601 date or timestamp. | 2026-10-15T00:00:00Z |
status |
string |
Optional | No | Standard | Checklists: OPEN, COMPLETED, MISSED. Incidents: OPEN, RESOLVED. Tips: SUBMITTED, CONFIRMED, VOID. Several separated by commas. | COMPLETED,MISSED |
location_id |
integer |
Optional | No | Standard | Only this work location. | 3 |
assigned_employee_id |
integer |
Optional | No | Standard | Checklists only: runs assigned to this employee. | 42 |
employee_id |
integer |
Optional | No | Standard | Tips only: this employee's declarations. | 42 |
severity |
enum |
Optional | No | Standard | Incidents only: LOW, MEDIUM, HIGH or CRITICAL. | HIGH |
category |
string |
Optional | No | Standard | Incidents only: a category code from the company's list. | SAFETY |
limit |
integer |
Optional | No | Standard | Page size from 1 to 500 (default 100). | 100 |
after_id |
integer |
Optional | No | Standard | Cursor: the meta.next_after_id of the previous page. | 5530 |
JSON body for creating a work order. Unknown fields answer 422 unknown_field; each invalid field answers 422 invalid_<field>.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
title |
string |
Required | No | Standard | What needs doing (up to 160 characters). | Fix the walk-in cooler door |
description |
string |
Optional | Yes | Standard | Details (up to 2,000 characters). | Door seal is torn on the left side. |
work_order_date |
date |
Optional | Yes | Standard | The day of the work. Default: today in the company's time zone. | 2026-10-16 |
due_at |
date-time |
Optional | Yes | Standard | When it is due. An offset is converted to the company's time zone; without one it is local time. | 2026-10-16T17:00:00-05:00 |
priority |
enum |
Optional | Yes | Standard | LOW, NORMAL (default), HIGH or URGENT. | HIGH |
location_id |
integer |
Optional | Yes | Standard | One of the company's work locations. | 3 |
site_id |
integer |
Optional | Yes | Standard | One of the company's customer sites, when customer sites are on. Labels the job with the site unless customer_label is sent. | 18 |
assigned_employee_id |
integer |
Optional | Yes | Standard | An active employee of the company. They are told in the app. | 42 |
crew_id |
integer |
Optional | Yes | Standard | One of the company's departments (the crew). | 7 |
customer_label |
string |
Optional | Yes | Standard | Customer or place (up to 160 characters). | Lobby |
code |
string |
Optional | Yes | Standard | Your reference or job number (up to 80 characters). Must not already be used: 409 duplicate_code. | WO-1042 |
window_start |
string |
Optional | Yes | Standard | Start of the time window on the work order date, 24-hour HH:MM. | 08:00 |
window_end |
string |
Optional | Yes | Standard | End of the time window, after window_start. | 12:00 |
One work order (job). Lists return data as an array of these with meta.row_count, limit, has_more and next_after_id; the single-record endpoint adds checklist_runs and incidents.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
id |
integer |
Required | No | Standard | Work order ID. | 1042 |
code |
string |
Required | Yes | Standard | Job number or external reference. | WO-1042 |
title |
string |
Required | No | Standard | What needs doing. | Fix the walk-in cooler door |
description |
string |
Required | Yes | Standard | Details. | Door seal is torn on the left side. |
status |
enum |
Required | No | Standard | REQUESTED (an employee asked for it), OPEN, IN_PROGRESS, COMPLETED or CANCELED. | OPEN |
priority |
enum |
Required | No | Standard | LOW, NORMAL, HIGH or URGENT. | HIGH |
work_order_date |
date |
Required | No | Standard | The day of the work. | 2026-10-16 |
due_at |
date-time |
Required | Yes | Standard | When it is due, company local time. | 2026-10-16 17:00:00 |
window_start |
date-time |
Required | Yes | Standard | Start of the time window. | 2026-10-16 08:00:00 |
window_end |
date-time |
Required | Yes | Standard | End of the time window. | 2026-10-16 12:00:00 |
route_order |
integer |
Required | Yes | Standard | Stop number in the crew's day. | 3 |
customer_label |
string |
Required | Yes | Standard | Customer or place. | Lobby |
location |
object |
Required | Yes | Standard | The work location as {id, name}, or null. | {"id": 3, "name": "Main St"} |
site |
object |
Required | Yes | Standard | The customer site as {id, name}, or null. | null |
assigned_employee |
object |
Required | Yes | Standard | The assigned employee as {id, name}, or null. | {"id": 42, "name": "Jordan Lee"} |
crew |
object |
Required | Yes | Standard | The crew (department) as {id, name}, or null. | {"id": 7, "name": "Maintenance"} |
requested_by_employee |
object |
Required | Yes | Standard | The employee who asked for it as {id, name}, or null. | null |
photo_count |
integer |
Required | No | Standard | Photos added to it. Photos themselves are never returned. | 2 |
signoff_count |
integer |
Required | No | Standard | Customer sign-offs that are not void. Signatures are never returned. | 1 |
started_at |
date-time |
Required | Yes | Standard | When work started. | 2026-10-16 08:05:00 |
completed_at |
date-time |
Required | Yes | Standard | When it was marked done. | null |
completed_by |
object |
Required | Yes | Standard | The staff user who marked it done, as {type: "user", id, name}; null when an employee finished it from My work. | null |
canceled_at |
date-time |
Required | Yes | Standard | When it was canceled or declined. | null |
cancel_reason |
string |
Required | Yes | Standard | Why it was canceled or declined. | null |
created_at |
date-time |
Required | Yes | Standard | Created. | 2026-10-16 07:12:44 |
updated_at |
date-time |
Required | Yes | Standard | Last changed. | 2026-10-16 07:12:44 |
checklist_runs |
array<object> |
Optional | No | Standard | Single-record endpoint only: linked checklist runs {id, name, status, date}. | [] |
incidents |
array<object> |
Optional | No | Standard | Single-record endpoint only, while incidents are on: linked incidents {id, title, severity, status, incident_date}. | [] |
One checklist run. Lists return data as an array of these; the single-record endpoint adds items.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
id |
integer |
Required | No | Standard | Checklist run ID. | 5531 |
checklist_id |
integer |
Required | Yes | Standard | The checklist (template) it was started from. | 12 |
name |
string |
Required | No | Standard | Checklist name. | Cooler check |
category |
string |
Required | Yes | Standard | OPENING, CLOSING, SIDE_WORK, TEMPERATURE, SAFETY, INSPECTION and others. | TEMPERATURE |
date |
date |
Required | No | Standard | The day it is for. | 2026-10-16 |
shift_label |
string |
Required | Yes | Standard | Shift or daypart. | Opening |
due_at |
date-time |
Required | Yes | Standard | When a scheduled run is due. | 2026-10-16 09:00:00 |
status |
enum |
Required | No | Standard | OPEN, COMPLETED or MISSED. | COMPLETED |
location |
object |
Required | Yes | Standard | The work location as {id, name}, or null. | {"id": 3, "name": "Main St"} |
area |
object |
Required | Yes | Standard | The work area as {id, name}, or null. | {"id": 4, "name": "Kitchen"} |
assigned_employee |
object |
Required | Yes | Standard | The assigned employee as {id, name}, or null. | {"id": 42, "name": "Jordan Lee"} |
work_order_id |
integer |
Required | Yes | Standard | The work order it belongs to. | null |
item_count |
integer |
Required | No | Standard | Items on the run. | 4 |
done_count |
integer |
Required | No | Standard | Items answered. | 4 |
required_left |
integer |
Required | No | Standard | Required items still open. | 0 |
flagged_count |
integer |
Required | No | Standard | Answers outside their limits. | 1 |
score |
number |
Required | Yes | Standard | Score percentage for scored checklists. | 92.5 |
photo_count |
integer |
Required | No | Standard | Photos added as proof. Photos themselves are never returned. | 1 |
has_photo_proof |
boolean |
Required | No | Standard | Whether any photo proof was added. | true |
completed_at |
date-time |
Required | Yes | Standard | When it was completed. | 2026-10-16 08:41:10 |
completed_by |
object |
Required | Yes | Standard | Who completed it: {type: "user" or "employee", id, name}. | {"type": "employee", "id": 42, "name": "Jordan Lee"} |
missed_at |
date-time |
Required | Yes | Standard | When it was marked missed. | null |
created_at |
date-time |
Required | Yes | Standard | Created. | 2026-10-16 05:00:02 |
updated_at |
date-time |
Required | Yes | Standard | Last changed. | 2026-10-16 08:41:10 |
items |
array<object> |
Optional | No | Standard | Single-record endpoint only: {id, label, type, required, done, value, unit, min_value, max_value, out_of_range, corrective_note, has_photo, completed_at, completed_by}. | [...] |
One incident from the log. Never includes the name of the child, client, resident or patient it is about, photos, or the OSHA injury log.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
id |
integer |
Required | No | Standard | Incident ID. | 88 |
title |
string |
Required | No | Standard | Short summary. | Guest slipped near the entrance |
description |
string |
Required | Yes | Conditional | What happened. Null for care companies (meta.descriptions_withheld). | Floor was wet after mopping. |
category |
string |
Required | No | Standard | Category code from the company's list. | SAFETY |
category_label |
string |
Required | No | Standard | The category's name. | Safety |
severity |
enum |
Required | No | Standard | LOW, MEDIUM, HIGH or CRITICAL. | HIGH |
status |
enum |
Required | No | Standard | OPEN or RESOLVED. | RESOLVED |
incident_date |
date |
Required | No | Standard | The day it happened. | 2026-10-14 |
occurred_at |
date-time |
Required | Yes | Standard | When it happened. | 2026-10-14 18:20:00 |
location |
object |
Required | Yes | Standard | The work location as {id, name}, or null. | {"id": 3, "name": "Main St"} |
employee |
object |
Required | Yes | Standard | The employee involved as {id, name}, or null. | null |
reported_by_employee |
object |
Required | Yes | Standard | The employee who reported it from My work as {id, name}, or null. | {"id": 42, "name": "Jordan Lee"} |
follow_up |
object |
Required | No | Standard | owner ({type: "user" or "employee", id, name}, or null) and due_date. | {"owner": null, "due_date": null} |
work_order_id |
integer |
Required | Yes | Standard | The work order it is linked to. | null |
photo_count |
integer |
Required | No | Standard | Photos attached. Photos themselves are never returned. | 2 |
resolved_at |
date-time |
Required | Yes | Standard | When it was resolved. | 2026-10-15 10:02:00 |
resolved_by |
object |
Required | Yes | Standard | The staff user who resolved it. | {"type": "user", "id": 7, "name": "Morgan Ellis"} |
resolution_note |
string |
Required | Yes | Conditional | How it was resolved. Null for care companies. | Wet floor signs added. |
reopened_at |
date-time |
Required | Yes | Standard | When it was last reopened. | null |
created_at |
date-time |
Required | Yes | Standard | Created. | 2026-10-14 18:25:31 |
updated_at |
date-time |
Required | Yes | Standard | Last changed. | 2026-10-15 10:02:00 |
Cash tips one employee declared for one shift or day. Needs operations.sensitive:read, which only an administrator can grant.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
id |
integer |
Required | No | Standard | Declaration ID. | 301 |
employee |
object |
Required | Yes | Standard | The employee as {id, name}, or null. | {"id": 42, "name": "Jordan Lee"} |
work_date |
date |
Required | No | Standard | The day worked. | 2026-10-14 |
time_entry_id |
integer |
Required | Yes | Standard | The shift (time entry) it covers; null for the whole day. | 99812 |
location |
object |
Required | Yes | Standard | The work location as {id, name}, or null. | {"id": 3, "name": "Main St"} |
amount_cents |
integer |
Required | No | Sensitive | Declared cash tips in cents. | 4650 |
amount |
number |
Required | No | Sensitive | The same in dollars. | 46.5 |
status |
enum |
Required | No | Standard | SUBMITTED (waiting for a manager), CONFIRMED (goes to the payroll export) or VOID. | CONFIRMED |
source |
enum |
Required | No | Standard | EMPLOYEE or MANAGER (who entered it). | EMPLOYEE |
declared_at |
date-time |
Required | Yes | Standard | When it was declared. | 2026-10-14 22:41:00 |
confirmed_at |
date-time |
Required | Yes | Standard | When a manager confirmed it. | 2026-10-15 09:10:00 |
voided_at |
date-time |
Required | Yes | Standard | When it was voided. | null |
created_at |
date-time |
Required | Yes | Standard | Created. | 2026-10-14 22:41:00 |
updated_at |
date-time |
Required | Yes | Standard | Last changed. | 2026-10-15 09:10:00 |
Payload of operations.work_order.created and operations.work_order.completed: the work order as the API lists it, and who acted.
| Field | Type | Presence | Nullable | Classification | Description | Example |
|---|---|---|---|---|---|---|
work_order |
OperationsWorkOrder |
Required | No | Standard | The work order, without checklist_runs and incidents. | {...} |
actor.type |
enum |
Required | No | Standard | api_client, user, employee or system (a customer site's repeat plan). | api_client |
actor.id |
integer |
Required | Yes | Standard | The API client, user or employee ID. | 5 |
actor.name |
string |
Required | No | Standard | Their name. | Facilities CRM |
Request base columns and select formats separately. The response uses the advertised output field, keeping names, dates, phone numbers, and money consistent with AppyShift.
| Field type | Format values | Example |
|---|---|---|
| Employee name | default, legal, last_first, preferred, initials | Lee, Jordan |
| Date | default, iso, us, european, long, month_day | 05/01/2026 |
| Phone | default, formatted, digits | (555) 123-4567 |
| Number | default, number, currency | $1,234.50 |
| Checkbox | default, checkmark | Yes |
Scopes are assigned to the OAuth client and can be narrowed again when requesting a token.
| Scope | Access | Classification |
|---|---|---|
employee_fields:read | List reportable employee field definitions and formats. | Standard |
employee_fields:write | Partially update API-exposed custom field values. | Standard |
employee_fields.sensitive:write | Update custom fields classified as sensitive. | Admin grant only |
reports:read | List report datasets and saved report definitions. | Standard |
reports:run | Run saved and ad-hoc reports. | Standard |
reports.sensitive:read | Include compensation, birth date, address, and other sensitive HR fields. | Admin grant only |
employees:read | Read the standard employee roster endpoint. | Standard |
employees:write | Update an employee payroll ID through the existing endpoint. | Standard |
credentials:read | Read employee certifications and licenses. | Standard |
timesheets:read | Read individual time entries. | Standard |
schedules:read | Read scheduled shifts. | Standard |
departments:read | Read departments and employee counts. | Standard |
positions:read | Read positions and employee counts. | Standard |
locations:read | Read work locations. | Standard |
time_off:read | Read time-off requests and balances. | Standard |
deductions:read | Read active employee deductions and employer matching amounts. | Admin grant only |
payroll:read | Read payroll runs and company totals, tax liabilities and deposits, and the payroll general ledger (companies with payroll on) | Standard |
payroll.statements:read | Read each employee's pay statements on payroll runs: earnings, deductions, taxes and net pay (administrator grant only) | Admin grant only |
recognition:read | Read shout-outs, points balances, badges, rewards and reward requests (Recognition) | Standard |
recognition:write | Send shout-outs, with points from a sender's monthly bank or the company's awards (Recognition) | Standard |
recruiting:read | Read job openings and applicants (name, email, phone, stage, source and dates) | Standard |
recruiting:write | Add applicants from a job board or form, move their stage and add notes | Standard |
applicants.sensitive:read | Include applicant details: screening answers, cover letter, resume file details, notes, rating and the not-selected reason | Admin grant only |
announcements:read | Read announcements with their audience, dates and acknowledgement counts | Standard |
announcements:write | Post announcements to everyone or one department, optionally by push and email | Standard |
surveys:read | Read surveys and their results as counts (never who answered or written answers) | Standard |
onboarding:read | Read new hires' onboarding progress, Form I-9 status and e-signature status (titles, statuses and dates only) | Standard |
visits:read | Read home care visits for payroll and billing reconciliation (times, caregiver, status, mileage; never client names, addresses or notes) | Standard |
operations:read | Read Operations work orders, checklist runs and incidents (only the sections the company has turned on) | Standard |
operations:write | Create Operations work orders from an external system | Standard |
operations.sensitive:read | Read cash tip declarations: what each employee declared per day (administrator grant only) | Admin grant only |
The reports.sensitive:read scope can only be granted by a Company Admin or Super Admin who also has sensitive-report export authority. The request must explicitly set include_sensitive.
Protected resource errors include a stable code, a readable message, and a request ID that can be matched to AppyShift access logs.
{
"error": {
"code": "missing_scope",
"message": "API token does not include the required scope.",
"request_id": "req_xxx"
}
}
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_json | The JSON request body could not be parsed. |
| 400 | invalid_scope | The token request asked for a scope the client was not granted. |
| 401 | invalid_client | The OAuth client credentials were rejected. |
| 401 | invalid_bearer_token | The access token is missing, expired, invalid, or revoked. |
| 403 | missing_scope | The token does not have the scope required by the endpoint. |
| 404 | report_not_found | The requested saved report does not exist in this company. |
| 413 | request_too_large | The report request body exceeded 256 KB. |
| 422 | invalid_dataset | The requested report dataset is unavailable. |
| 422 | invalid_view | The selected resource view is not supported. |
| 422 | invalid_metadata | Report metadata is not a valid bounded flat key/value object. |
| 422 | invalid_custom_field | A custom field is inactive, non-reportable, unknown, or malformed. |
| 422 | invalid_custom_field_value | A custom field value does not match its configured type or options. |
| 429 | rate_limited | The client or IP exceeded the current request limit. |
Protected resources currently use the /api/v1 prefix. Additive response fields may appear within a version; integrations should ignore unknown properties. Breaking path, request, or response changes will use a new API version.
aps_live_ keys remain supported for existing integrations, but new clients should use OAuth.