Skip to documentation

AppyShift API · v1 · Public beta

Build trusted workforce integrations.

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.

Base URL https://www.appyshift.com/{company_slug}
51
Documented endpoints
28
Webhook events
98
Field-level schemas
OAuth 2.0
Tenant-scoped access

Overview

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.

Authorization required

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.

Tenant model

  • Replace {company_slug} with the client’s AppyShift portal slug.
  • A client created for one company cannot read another company’s data.
  • The company must have Integrations Hub enabled.
  • Requests are audited and rate-limited.

Request API access

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.

01

Identify the company

Provide the AppyShift company name and portal slug, plus an authorized business contact and a technical contact.

02

Describe the integration

Explain the system being connected, the business purpose, expected request volume, and whether webhooks or write access are needed.

03

Confirm data access

List the resources and scopes required. Requests involving sensitive report fields receive an additional authorization review.

Ready to connect?

Ask Support to authorize API service.

After approval, an AppyShift Super Admin provisions a named OAuth client and coordinates the one-time credential handoff.

Authentication

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.

Credentials are not recoverable

Client secrets are password-hashed and access tokens are SHA-256 hashed. Rotating a secret or revoking a client immediately invalidates its issued tokens.

Quick start

Once your intended integration is approved, connect it in four controlled steps.

Request authorization

Contact Support with the company, integration purpose, technical contact, and data access required.

Receive OAuth credentials

An AppyShift Super Admin provisions a named client with approved scopes. Capture the one-time client secret securely.

Inspect access

Request a token, then call /api/v1/capabilities to confirm the tenant, expiry, scopes, and available operations.

Sync, report, or subscribe

Read workforce resources, run an approved report, perform permitted writes, or receive signed webhook events.

API conventions

These rules apply across the protected REST API unless an endpoint documents a narrower limit or a different response field.

Protected request
curl --request GET \
  "https://www.appyshift.com/acme/api/v1/employees?limit=100" \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --header "Accept: application/json"
Typical collection response
{
  "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
    }
  }
}

Shared behavior

HTTP and encoding

JSON on protected resources

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
Access tokens

Short-lived bearer access

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}
Tenant boundary

Company slug plus client

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/...
Response anatomy

Data, metadata, and tracing

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
Field semantics

Respect types and nullability

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
Partial updates

PATCH changes submitted fields only

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

Follow endpoint cursors

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
Validation and errors

Stable machine-readable codes

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

Current limits

120Requests per minute

Per API client across its active access tokens

300Requests per minute

Per source IP within a company portal

30Authentication failures

Per minute and source IP

256 KBJSON request body

Maximum raw body accepted for an API write

Plan retries without relying on rate-limit headers

HTTP 429 is the stable signal today. Use bounded exponential backoff with jitter; Retry-After and remaining-quota headers are not currently guaranteed.

Retry behavior

OperationPolicyGuidance
GET resources and catalogsSafe to retryRepeat the same request after a temporary failure. Preserve filters and use the returned cursor for the next page.
POST /api/v1/reports/runRead-only executionA retry does not mutate workforce records, but it creates another access-log entry and consumes rate-limit capacity.
PATCH employee fieldsRead back firstIf the response is lost, retrieve the employee field values before retrying. Repeated writes can create additional audit activity.
Webhook deliveriesDeduplicateStore X-AppyShift-Delivery as the idempotency key. REST writes do not currently accept a generic Idempotency-Key header.

Production integration checklist

  1. Keep client credentials and access tokens in a server-side secret manager; never embed them in browser or mobile code.
  2. Grant only the scopes the integration needs, and request a narrower scope subset when practical.
  3. Cache an access token until shortly before expires_in, then obtain a replacement with client credentials.
  4. Treat omitted and null fields according to the linked schema instead of guessing from display output.
  5. Follow meta.pagination.has_more and next_after_id whenever cursor pagination is enabled.
  6. Back off after HTTP 429 and temporary 5xx responses; rate-limit response headers are not currently guaranteed.
  7. Retain request_id with operational logs, but exclude secrets and sensitive employee payloads.
  8. Read a resource back before retrying a write whose response was interrupted.
  9. Verify webhook signatures against the raw request body and deduplicate X-AppyShift-Delivery.

Endpoints

All API paths below are appended to the company-specific base URL. They are grouped by function.

Access and capabilities

POST/oauth/token
Client credentials

Create an access token

Exchange a client ID and one-time client secret for a short-lived bearer token.

  • Form-encoded request
  • Access token expires in up to one hour
  • Response is never cacheable
View request and response examples
Request
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"
Response
{
  "access_token": "aps_oauth_xxx",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "employee_fields:read reports:read reports:run"
}
GET/api/v1/capabilities
Authenticated token

Inspect token capabilities

Returns the current company, authentication type, granted scopes, expiry information, and only the operations this token can call.

  • No additional scope is required
  • Useful for connection tests and dynamic integration setup
  • Operations are filtered to the token’s granted scope subset
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/capabilities \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}

People and company setup

GET/api/v1/employees
employees:read

List employees

Returns the employee roster with status, department, position, payroll identifier, and updated timestamp.

  • Filters: status, department_id, updated_since
  • Optional cursor pagination: limit and after_id
  • Maximum page size: 500
View request and response examples
Request
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"
Response
{
  "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
    }
  }
}
GET/api/v1/employees/{employee_id}
employees:read

Retrieve an employee

Returns one employee’s standard non-sensitive profile and organization relationships.

  • Sensitive and custom values use the field-values endpoint
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/employees/42 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}
GET/api/v1/employees/{employee_id}/fields
employees:read + employee_fields:read

Retrieve employee field values

Returns selected reportable values using the same formats advertised by the employee-field catalog.

  • Select fields with fields=employee_name,hire_date,custom_17
  • Select formats with formats[hire_date]=us
  • Sensitive values additionally require reports.sensitive:read and include_sensitive=1
View request and response examples
Request
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"
Response
{
  "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
  }
}
PATCH/api/v1/employees/{employee_id}/fields
employee_fields:write

Update custom field values

Partially updates active, reportable custom fields. Omitted fields remain unchanged.

  • Use custom_N keys returned by the field catalog
  • Maximum 100 fields per request
  • Sensitive custom fields require employee_fields.sensitive:write
View request and response examples
Request
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
    }
  }'
Response
{
  "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"]
  }
}
GET/api/v1/employee-fields
employee_fields:read

List employee fields

Returns reportable system and custom field definitions, choice options, and supported output formats.

  • Add include_sensitive=1 only with reports.sensitive:read
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/employee-fields \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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
  }
}
GET/api/v1/credentials
credentials:read

List employee credentials

Returns employee certifications and licenses with issue, expiry, verification, and status information.

  • Optional filters: employee_id, status, expiring_within_days
View request and response examples
Request
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"
Response
{
  "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}
}
GET/api/v1/departments
departments:read

List departments

Returns departments with descriptions, display colors, and active employee counts.

View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/departments \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "data": [{"id": 7, "name": "Front Desk", "description": "Guest arrival team", "color": "#2563eb", "employee_count": 12}],
  "meta": {"request_id": "req_xxx", "row_count": 1}
}
GET/api/v1/positions
positions:read

List positions

Returns job positions with descriptions, department names, and active employee counts.

View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/positions \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}
GET/api/v1/locations
locations:read

List work locations

Returns work-location addresses, coordinates, geofence settings, status, and active employee counts.

View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/locations \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}

Scheduling and time

GET/api/v1/timesheets
timesheets:read

List time entries

Returns completed clock-in and clock-out entries for a required date range.

  • Requires start_date and end_date
  • Maximum range: 63 calendar days
  • Overnight entries are returned with the correct clock-out date
View request and response examples
Request
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"
Response
{
  "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}
}
GET/api/v1/schedules
schedules:read

List scheduled shifts

Returns employee shift assignments, times, status, position, department, location, and notes for a required date range.

  • Requires start_date and end_date
  • Maximum range: 63 calendar days
View request and response examples
Request
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"
Response
{
  "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}
}
GET/api/v1/time-off
time_off:read

List time-off requests or balances

Returns time-off requests for a date range or employee leave balances for a year.

  • view=requests supports start_date, end_date, and employee_id
  • view=balances supports year
  • Request ranges are limited to 366 calendar days
View request and response examples
Request
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"
Response
{
  "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}
}

Payroll

POST/api/v1/employees/{employee_id}/payroll-id
employees:write

Update a payroll identifier

Assigns or clears the external payroll identifier for one employee.

  • Available when payroll processing is enabled
  • Send an empty payroll_id to clear the value
  • Maximum length: 80 characters
View request and response examples
Request
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"}'
Response
{
  "data": {
    "id": 42,
    "name": "Jordan Lee",
    "email": "jordan.lee@example.com",
    "payroll_id": "EE-1042",
    "active": true
  },
  "meta": {"request_id": "req_xxx"}
}
GET/api/v1/deductions
deductions:read

List employee deductions

Returns active deduction elections, employee amounts, and employer matching values.

  • Optional employee_id filter
  • Available when payroll processing is enabled
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/deductions \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "employee_id=42"
Response
{
  "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}
}
GET/api/v1/payroll/runs
payroll:read

List payroll runs

Returns 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.

  • Filters: pay_date_from, pay_date_to, status (comma-separated APPROVED, PAYMENT_STAGED, PAID, VOID)
  • include_unapproved=1 adds calculated payrolls that are not approved yet (status CALCULATED); their amounts can still change
  • Cursor pagination by run ID: limit (1-500, default 100) and after_id
  • correction and void_reversal mark a reversing payroll made when a pay statement was voided
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
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"
Response
{
  "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}
  }
}
GET/api/v1/payroll/runs/{run_id}
payroll:read

Retrieve a payroll run

Returns one payroll run with its totals by earning code, deduction code and tax. No line names an employee.

  • A run ID from another company, a draft, or a calculated run without include_unapproved=1 answers 404 payroll_run_not_found
  • Tax codes: FIT, SS, MED, ADDL_MED, FUTA, SIT, SUI, SDI, LOCAL and others
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/payroll/runs/318 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}
GET/api/v1/payroll/runs/{run_id}/statements
payroll.statements:read

List pay statements on a run

Returns 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.

  • Sensitive scope: only a Company Admin can grant payroll.statements:read
  • payment_method is CHECK, ACH or MANUAL (null when none); no account or routing numbers
  • voided marks a statement voided after it was paid; void_reversal marks the reversing statement
  • Cursor pagination by statement ID: limit (1-500, default 100) and after_id
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/payroll/runs/318/statements \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "limit=100"
Response
{
  "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}
  }
}
GET/api/v1/payroll/tax-liabilities
payroll:read

Payroll tax liabilities

Returns tax liability by tax and jurisdiction for payrolls paid in a quarter, the way the Taxes section adds it up, with the payrolls included.

  • year and quarter default to the current quarter in the company time zone
  • Counts approved, payment staged and paid payrolls; include_unapproved=1 adds calculated ones
  • Amounts are the stored pay statement amounts, including lines changed by hand
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
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"
Response
{
  "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": []}
}
GET/api/v1/payroll/tax-deposits
payroll:read

Payroll tax deposits

Returns 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.

  • status: due, partial, overdue, scheduled, paid, late or none
  • AppyShift does not pay taxes: recorded amounts are the deposits the company recorded in the Taxes section
  • year and quarter default to the current quarter in the company time zone
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
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"
Response
{
  "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": []}
}
GET/api/v1/payroll/general-ledger
payroll:read

Payroll general ledger

Returns 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.

  • Either pay_date_from and pay_date_to (at most 366 days) or run_id
  • Accounts come from the GL accounts on earning and deduction codes and in Payroll setup; lines without one show as Unmapped
  • A run that is not approved yet answers 422 run_not_finalized
  • Lines are split by department only for a token that also has payroll.statements:read (a one-person department would show that person's pay); otherwise department is null and meta.by_department is false
  • Answers 404 payroll_not_enabled unless the company has payroll on
View request and response examples
Request
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"
Response
{
  "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}
  }
}

Reports

GET/api/v1/reports
reports:read

List reports and datasets

Returns saved report definitions and the datasets and columns available to the token.

  • Definitions are filtered before they leave AppyShift
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/reports \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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
  }
}
POST/api/v1/reports/run
reports:run

Run a report

Runs a saved report by report_id or an ad-hoc report using a dataset, columns, formats, labels, and filters.

  • Returns only requested, authorized columns
  • Optional metadata is echoed as meta.client_metadata
  • JSON body limit: 256 KB
View request and response examples
Request
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"
    }
  }'
Response
{
  "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"
    }
  }
}

Recognition

GET/api/v1/recognition/shout-outs
recognition:read

List shout-outs

Returns 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.

  • Filters: created_from and created_to (YYYY-MM-DD, inclusive), employee_id (sent to or by), status (published by default; pending, hidden, rejected or all)
  • Cursor pagination: limit (1-500, default 100) and after_id; meta.pagination.next_after_id
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
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"
Response
{
  "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}
  }
}
POST/api/v1/recognition/shout-outs
recognition:write

Send a shout-out

Recognizes 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.

  • Fields: to_employee_ids, message, from_employee_id, value, points, award
  • Without from_employee_id the shout-out is from the company and shows your integration's name
  • Peer points need from_employee_id; they follow the company's limits (most per shout-out, monthly bank, once per coworker a month)
  • Returns 201 with the created shout-outs; fires recognition.shout_out.created when each goes live
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
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
  }'
Response
{
  "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}
}
GET/api/v1/recognition/points
recognition:read

List points balances

Returns each employee's points: earned, redeemed for rewards, available to spend, and pending approval.

  • Filter: employee_id (returns that employee even with no points)
  • Paged by employee ID: limit and after_id
  • meta.points_enabled tells whether points are on for the company
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/recognition/points \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "limit=100"
Response
{
  "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
  }
}
GET/api/v1/recognition/badges
recognition:read

List badges

Returns 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).

  • Optional employee_id
  • meta.badges_enabled tells whether the company shows badges
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/recognition/badges \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}
GET/api/v1/recognition/rewards
recognition:read

List rewards

Returns the company's rewards store: each reward's point price, type (ITEM, CASH or PTO), value and stock.

  • Active rewards only unless include_inactive=true
  • meta.rewards_store_open tells whether employees can redeem now
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/recognition/rewards \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}
GET/api/v1/recognition/redemptions
recognition:read

List reward requests

Returns employees' reward requests and what a manager decided. CASH rewards are paid as taxable pay through payroll when fulfilled.

  • Filters: status (requested, fulfilled, declined), employee_id
  • Cursor pagination: limit (1-500, default 100) and after_id; meta.pagination.next_after_id
  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/recognition/redemptions \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "status=requested"
Response
{
  "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}
  }
}
GET/api/v1/recognition/values
recognition:read

List recognition values

Returns what a shout-out can recognize (Teamwork, Covered a shift and so on): the keys POST /api/v1/recognition/shout-outs accepts as value.

  • Answers 404 recognition_not_enabled when Recognition is off or not on the plan, and 404 feature_not_installed before its migrations run
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/recognition/values \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "data": [
    {"key": "TEAMWORK", "label": "Teamwork"},
    {"key": "COVERED_SHIFT", "label": "Covered a shift"}
  ],
  "meta": {"request_id": "req_xxx", "row_count": 2}
}

Recruiting

GET/api/v1/jobs
recruiting:read

List job openings

Returns 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.

  • Filter: status (DRAFT, OPEN, PAUSED, CLOSED, FILLED)
  • Cursor pagination: limit (1 to 500) and after_id
  • Requires recruiting on the company's plan (Growth and up)
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/jobs \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "status=OPEN" \
  --data-urlencode "limit=50"
Response
{
  "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 }
}
GET/api/v1/applicants
recruiting:read

List applicants

Returns applications oldest first: name, email, phone, stage, source and dates. A token with applicants.sensitive:read also gets each applicant's details.

  • Filters: job_id, stage, updated_since
  • Cursor pagination: limit (1 to 500) and after_id
  • Archived applications and voluntary EEO answers are never returned
View request and response examples
Request
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"
Response
{
  "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 }
}
GET/api/v1/applicants/{applicant_id}
recruiting:read

Retrieve an applicant

Returns one applicant with its stage history and interview times. With applicants.sensitive:read: details and the team's notes.

  • An applicant from another company answers 404 applicant_not_found
  • Resume files are never returned, only their name, type and size
View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/applicants/5012 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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 }
}
POST/api/v1/applicants
recruiting:write

Add an applicant

Adds 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.

  • Duplicate email for the same job answers 409 duplicate_application
  • resume_url is checked but not kept: AppyShift stores uploaded files, never links, and never fetches the address
  • Emails the hiring team like a careers page application (the job's hiring manager and the company's recruiting email)
  • Sends recruiting.applicant.created
View request and response examples
Request
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"
  }'
Response
{
  "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 }
}
PATCH/api/v1/applicants/{applicant_id}
recruiting:write

Move an applicant or add a note

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.

  • decline_reason goes with stage DECLINED
  • expected_updated_at refuses the change with 409 applicant_changed if the applicant moved since you read it
  • Sends recruiting.applicant.stage_changed, and recruiting.applicant.hired on a move to HIRED
View request and response examples
Request
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"
  }'
Response
{
  "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 }
}

Communication

GET/api/v1/announcements
announcements:read

List announcements

Returns the company's announcements (scheduled, active and expired) with the plain-text body, audience, publish and expiry times, author, and acknowledgement and read counts.

  • Optional filters: published_from and published_to (YYYY-MM-DD, the company calendar)
  • Ordered by announcement ID; page with limit (1-500, default 100) and after_id = meta.next_after_id
  • Times are the company's wall-clock times; meta.timezone names the zone
  • Answers 404 communication_not_enabled when announcements are off or not on the plan (Growth and up)
  • Private messages and chats are not available through the API
View request and response examples
Request
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"
Response
{
  "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
  }
}
GET/api/v1/announcements/{announcement_id}
announcements:read

Retrieve an announcement

Returns one announcement of this company. Another company's ID answers 404 announcement_not_found.

  • Same fields as the list
View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/announcements/318 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}
POST/api/v1/announcements
announcements:write

Post an announcement

Posts 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.

  • Accepted fields: title, body, priority, audience, publish_at, expires_at, require_acknowledgement, deliver; any other field is a 422
  • A title or a body is required; body is plain text (up to 20,000 characters)
  • audience: "everyone" (the default) or {"type":"department","department_id":12}; there is no location or position audience
  • publish_at and expires_at: YYYY-MM-DD or an ISO 8601 date and time, read on the company clock unless they carry an offset
  • deliver: ["push"], ["email"] or both; sent at the publish time. Texts are sent only by a company admin in AppyShift
  • Answers 201 with the announcement; meta.delivery lists the channels queued
View request and response examples
Request
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"]
  }'
Response
{
  "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}
  }
}
GET/api/v1/surveys
surveys:read

List surveys

Returns the company's surveys with question counts and participation (assigned, completed, response rate).

  • Optional filter: active=true or active=false
  • Ordered by survey ID; page with limit (1-500, default 100) and after_id = meta.next_after_id
  • Answers 404 communication_not_enabled when surveys are off or not on the plan (Growth and up)
View request and response examples
Request
curl --get \
  https://www.appyshift.com/acme/api/v1/surveys \
  --header "Authorization: Bearer aps_oauth_xxx" \
  --data-urlencode "active=true"
Response
{
  "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}
}
GET/api/v1/surveys/{survey_id}/results
surveys:read

Retrieve survey results

Returns 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.

  • Only completed responses count; a skipped question is not counted
  • Answers to a choice that was later removed are counted under "Removed option"
View request and response examples
Request
curl https://www.appyshift.com/acme/api/v1/surveys/12/results \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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}
}

Onboarding

GET/api/v1/onboarding
onboarding:read

List new hires' onboarding

One 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.

  • status: in_progress or completed
  • started_since: ISO 8601 date or timestamp; onboarding started on or after it
  • Cursor pagination: limit (1-500, default 100) and after_id (meta.pagination.next_after_id)
  • Ordered by employee_id
View request and response examples
Request
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"
Response
{
  "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}
  }
}
GET/api/v1/onboarding/{employee_id}
onboarding:read

Get one new hire's onboarding

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.

  • 404 onboarding_not_found when the employee has no onboarding or belongs to another company
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/onboarding/42 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}

Home care

GET/api/v1/home-care/visits
visits:read

List home care visits

Returns 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.

  • Requires date_from and date_to (YYYY-MM-DD), at most 62 days
  • Optional filters: employee_id, status (comma-separated)
  • Ordered by visit ID; page with limit (1-500, default 100) and after_id = meta.next_after_id
  • Answers 404 home_care_not_enabled when the company has home care off
View request and response examples
Request
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"
Response
{
  "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
  }
}

Operations

GET/api/v1/operations/work-orders
operations:read

List work orders

Returns 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.

  • Filters: status (REQUESTED, OPEN, IN_PROGRESS, COMPLETED, CANCELED; comma separated), location_id, site_id, assigned_employee_id, from and to (work order date), updated_since
  • Cursor pagination: limit (1-500, default 100) and after_id; results are oldest ID first
  • Answers 404 section_not_enabled unless the company has this Operations section turned on (Work orders)
  • Photos and signatures are never returned, only counts
View request and response examples
Request
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"
Response
{
  "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"}
  }
}
GET/api/v1/operations/work-orders/{work_order_id}
operations:read

Retrieve a work order

Returns one work order with the checklist runs and incidents linked to it.

  • Another company's ID answers 404 work_order_not_found
  • Answers 404 section_not_enabled unless the company has this Operations section turned on (Work orders)
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/operations/work-orders/1042 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}
POST/api/v1/operations/work-orders
operations:write

Create a work order

Adds 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.

  • Accepted fields: title (required), description, work_order_date, due_at, priority, location_id, site_id, assigned_employee_id, crew_id, customer_label, code, window_start, window_end
  • Unknown fields and invalid values answer 422 with a code naming the field
  • A code already used by another work order answers 409 duplicate_code, so a retried request does not add a second job
  • Without a code, the company's job number prefix applies
  • The audit log names the API client; sends operations.work_order.created
  • Answers 201 Created with the work order
View request and response examples
Request
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"
  }'
Response
{
  "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}
}
GET/api/v1/operations/checklists
operations:read

List checklist runs

Returns checklist runs (opening, closing, temperature logs and other checks) with completion status, item totals, items outside their limits, and who completed them.

  • Filters: from and to (checklist date), updated_since, status (OPEN, COMPLETED, MISSED), location_id, assigned_employee_id
  • Without from, to or updated_since: the last 30 days
  • Photo proof is a count and a flag; photos are never returned
  • Cursor pagination: limit and after_id
  • Answers 404 section_not_enabled unless the company has this Operations section turned on (Checklists)
View request and response examples
Request
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"
Response
{
  "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"}}
}
GET/api/v1/operations/checklists/{checklist_run_id}
operations:read

Retrieve a checklist run

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.

  • Photo items say has_photo only
  • Another company's ID answers 404 checklist_not_found
View request and response examples
Request
curl \
  https://www.appyshift.com/acme/api/v1/operations/checklists/5531 \
  --header "Authorization: Bearer aps_oauth_xxx"
Response
{
  "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"}
}
GET/api/v1/operations/incidents
operations:read

List incidents

Returns 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.

  • Filters: from and to (incident date), updated_since, status (OPEN, RESOLVED), severity, category, location_id
  • Without from, to or updated_since: the last 30 days
  • Never returns the name of the child, client, resident or patient an incident is about
  • Care companies (home care, long-term care, healthcare, child care): description and resolution_note are null (meta.descriptions_withheld)
  • The OSHA injury and illness log is not available through the API
  • Answers 404 section_not_enabled unless the company has this Operations section turned on (Incidents)
View request and response examples
Request
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"
Response
{
  "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}
}
GET/api/v1/operations/tip-declarations
operations.sensitive:read

List cash tip declarations

Returns the cash tips each employee declared, per shift or per day, with whether a manager confirmed them for payroll.

  • Administrator grant only (compensation data)
  • Filters: from and to (work date), updated_since, status (SUBMITTED, CONFIRMED, VOID), employee_id, location_id
  • Void declarations only when status includes VOID
  • Without from, to or updated_since: the last 30 days
  • Answers 404 section_not_enabled unless the company has this Operations section turned on (Cash tips, restaurants and hotels)
View request and response examples
Request
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"
Response
{
  "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"}}
}

Webhooks

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.

Configure webhooks in Integrations Hub

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.

Available events

Access and capabilities

People and company setup

Scheduling and time

pto.requested
Time-off request submitted

An employee, manager, or administrator submits a time-off request. The legacy pto name applies to every supported leave type.

View TimeOffRequestedWebhookPayload

Payroll

payroll.run.approved
Payroll run approved

A calculated payroll is approved (after the second approval when the company requires two).

View PayrollRunWebhookPayload
payroll.run.paid
Payroll run paid

A payroll is marked paid, by a person or by automatic payment. Reversing payrolls made when a pay statement is voided do not send it.

View PayrollRunWebhookPayload

Recognition

recognition.shout_out.created
Recognition shout-out sent

A 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.

View RecognitionShoutOutCreatedWebhookPayload

Recruiting

recruiting.applicant.stage_changed
Applicant stage changed

An 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.

View RecruitingApplicantStageWebhookPayload

Communication

announcement.published
Announcement published

An 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.

View AnnouncementPublishedWebhookPayload

Onboarding

onboarding.started
Employee onboarding started

An 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).

View OnboardingStartedWebhookPayload

Training

training.assigned
Training assigned

A 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.

View TrainingWebhookPayload
training.completed
Training completed

An employee passes a course or quick quiz in AppyShift, or staff record or import training taken elsewhere. Pro plan.

View TrainingWebhookPayload
training.certification_recorded
Training certification recorded

Passing a course that counts as a certification records the employee's certification. Pro plan.

View TrainingWebhookPayload

Operations

operations.work_order.created
Work order created

A 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.

View OperationsWorkOrderWebhookPayload
operations.work_order.completed
Work order completed

A 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.

View OperationsWorkOrderWebhookPayload

Delivery contract

HeaderMeaning
Content-Typeapplication/json
X-AppyShift-EventEvent name, matching the envelope's event property.
X-AppyShift-DeliveryStable delivery ID. Persist it as an idempotency key so a retry does not apply the event twice.
X-AppyShift-TimestampUnix timestamp included when a signing credential is attached.
X-AppyShift-Signaturesha256= followed by the lowercase HMAC-SHA256 signature.
  • Return any 2xx status after safely accepting the event. Other responses are treated as delivery failures.
  • Process events idempotently and do not depend on delivery order. Failed deliveries are retried, and administrators can manually retry a failed delivery from Activity.
  • Use HTTPS and attach a signing credential. Reject old timestamps in your receiver to reduce replay risk.
  • Employee events can contain phone and compensation data. Limit Integrations Hub access and endpoint logs to trusted administrators.

Verify signatures

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.

PHP signature verification
$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');
}

Event examples

Schedule published
schedule.published
{
  "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"
}
Time-off request submitted
pto.requested
{
  "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"
}
Time-off request approved
pto.approved
{
  "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"
}
Time-off request denied
pto.denied
{
  "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"
}
Time-off request cancelled
pto.cancelled
{
  "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"
}
Time entry approved
time_entry.approved
{
  "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"
}
Time entry rejected
time_entry.rejected
{
  "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"
}
Shift coverage approved
shift_swap.approved
{
  "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"
}
Shift coverage rejected
shift_swap.rejected
{
  "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"
}
Employee onboarding completed
onboarding.completed
{
  "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"
}
Training completed
training.completed
{
  "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"
}
Payroll exported
payroll.exported
{
  "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"
}
Tip pool approved
tip_pool.approved
{
  "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"
}
Payroll run approved
payroll.run.approved
{
  "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"
}
Payroll run paid
payroll.run.paid
{
  "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"
}
Recognition shout-out sent
recognition.shout_out.created
{
  "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"
}
Applicant added
recruiting.applicant.created
{
  "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"
}
Applicant stage changed
recruiting.applicant.stage_changed
{
  "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"
}
Applicant hired
recruiting.applicant.hired
{
  "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"
}
Announcement published
announcement.published
{
  "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"
}
Employee onboarding started
onboarding.started
{
  "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"
}
Work order created
operations.work_order.created
{
  "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"
}
Work order completed
operations.work_order.completed
{
  "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"
}

Schema reference

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.

98 schemas

Access and capabilities 4 schemas

Schema · 2 fields

OAuthTokenRequest

Form fields accepted by the client-credentials token endpoint. Client authentication is sent separately with HTTP Basic authentication.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 4 fields

OAuthTokenResponse

Short-lived bearer credential returned after successful client authentication.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 13 fields

ApiCapabilitiesResponse

Identity and operation discovery for the bearer token used on the request.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 3 fields

IntegrationTestWebhookPayload

Payload queued from Integrations Hub to verify endpoint configuration and delivery.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

People and company setup 15 schemas

Schema · 3 fields

CredentialListQuery

Optional filters for employee certifications and licenses.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 10 fields

CredentialCollectionResponse

Employee certification and license records.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 5 fields

DepartmentCollectionResponse

Company departments and current active employee counts.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 5 fields

PositionCollectionResponse

Company job positions and current active employee counts.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

LocationCollectionResponse

Company work locations, addresses, and time-clock geofence settings.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 5 fields

EmployeeListQuery

Optional query parameters for filtering and cursor-paginating the employee roster.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 19 fields

EmployeeListResponse

A standard employee roster page. Sensitive profile and custom values are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 23 fields

EmployeeDetailResponse

One employee’s standard non-sensitive profile and organization relationships.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 3 fields

EmployeeFieldValuesQuery

Query parameters for selecting reportable fields and their display formats for one employee.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

EmployeeFieldValuesResponse

Formatted reportable values for one employee. Keys inside values depend on selected fields and formats.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 2 fields

CustomFieldUpdateRequest

Partial update body for active, reportable custom employee fields. Omitted fields remain unchanged.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 4 fields

CustomFieldUpdateResponse

Normalized values returned after a successful partial custom-field update.

#
FieldTypePresenceNullableClassificationDescriptionExample
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"]
Schema · 1 field

EmployeeFieldCatalogQuery

Optional query parameter controlling whether sensitive field definitions are visible.

#
FieldTypePresenceNullableClassificationDescriptionExample
include_sensitive boolean Optional No Sensitive Set to 1 only with reports.sensitive:read. 0
Schema · 19 fields

EmployeeFieldCatalogResponse

Field definitions used to build selectors, validate custom-field writes, and request consistent output formats.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 37 fields

EmployeeWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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"}

Scheduling and time 14 schemas

Schema · 2 fields

DateRangeQuery

Required inclusive date range shared by time-entry and schedule feeds.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

TimesheetCollectionResponse

Completed time entries within the requested date range.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

ScheduleCollectionResponse

Scheduled shift assignments within the requested date range.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 5 fields

TimeOffQuery

Selects either request history or annual leave balances.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 17 fields

TimeOffCollectionResponse

Time-off request rows or leave-balance rows selected by the view query.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 10 fields

SchedulePublishedWebhookPayload

Payload produced when a full or scoped weekly schedule publication changes the employee-visible schedule.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 9 fields

TimeOffRequestedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

TimeOffApprovedWebhookPayload

Payload produced when a time-off request moves to approved. Free-text reasons and reviewer notes are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

TimeOffDeniedWebhookPayload

Payload produced when a time-off request moves to denied. Free-text reasons and reviewer notes are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

TimeOffCancelledWebhookPayload

Payload produced when a manager or administrator moves a time-off request to cancelled. Free-text reasons and reviewer notes are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

TimeEntryApprovedWebhookPayload

Payload produced after a reviewed time entry is approved.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

TimeEntryRejectedWebhookPayload

Payload produced after a reviewed time entry is rejected. Free-text review notes are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 16 fields

ShiftSwapApprovedWebhookPayload

Payload produced after a shift swap or shift-board pickup is approved.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 16 fields

ShiftSwapRejectedWebhookPayload

Payload produced after a manager rejects a shift swap or shift-board pickup. Free-text notes are intentionally excluded.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Payroll 17 schemas

Schema · 1 field

EmployeeFilterQuery

Optional filter used by employee-associated collection feeds.

#
FieldTypePresenceNullableClassificationDescriptionExample
employee_id integer Optional No Standard Return rows for one employee. 42
Schema · 8 fields

DeductionCollectionResponse

Active employee deduction elections and employer matching amounts.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 1 field

PayrollIdUpdateRequest

JSON body assigning or clearing one employee’s external payroll identifier.

#
FieldTypePresenceNullableClassificationDescriptionExample
payroll_id string Required No Conditional External payroll identifier up to 80 characters. Send an empty string to clear it. EE-1042
Schema · 6 fields

PayrollIdUpdateResponse

Employee identity summary after a payroll-ID update.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

PayrollExportedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 13 fields

TipPoolApprovedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 6 fields

PayrollRunListQuery

Optional filters for listing payroll runs.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 29 fields

PayrollRunCollectionResponse

Payroll runs with company totals, oldest run ID first. No employee data.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 3 fields

PayrollRunLookupQuery

Options for one payroll run and its pay statements.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 41 fields

PayrollRunDetailResponse

One payroll run with totals by earning code, deduction code and tax. Company totals only.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 44 fields

PayrollStatementCollectionResponse

Each employee's pay statement on a run. Needs payroll.statements:read. Never includes Social Security numbers, addresses, bank, routing or account numbers.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 3 fields

PayrollTaxPeriodQuery

The quarter for tax liabilities and deposits. Defaults to the current quarter in the company time zone.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 28 fields

PayrollTaxLiabilityResponse

Tax liability by tax and jurisdiction for payrolls paid in the quarter.

#
FieldTypePresenceNullableClassificationDescriptionExample
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. []
Schema · 23 fields

PayrollTaxDepositResponse

Tax deposits due for the quarter and the year's FUTA deposits, with what the company recorded as deposited.

#
FieldTypePresenceNullableClassificationDescriptionExample
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. []
Schema · 3 fields

PayrollGeneralLedgerQuery

Either a pay date range or one payroll run.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 26 fields

PayrollGeneralLedgerResponse

One journal entry per payroll, dated on its pay date, as the General ledger detail report shows it.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 20 fields

PayrollRunWebhookPayload

Payload of payroll.run.approved and payroll.run.paid: the payroll run with company totals. No employee names, statements, pay rates or bank details.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Reports 4 schemas

Schema · 1 field

ReportCatalogQuery

Optional query parameter controlling sensitive saved definitions, datasets, and columns.

#
FieldTypePresenceNullableClassificationDescriptionExample
include_sensitive boolean Optional No Sensitive Set to 1 only with reports.sensitive:read. 0
Schema · 17 fields

ReportCatalogResponse

Saved report definitions plus the datasets and columns currently available to the token.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 8 fields

ReportRunRequest

JSON body for a saved or ad-hoc report. Ad-hoc selections override the corresponding saved-report values.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

ReportRunResponse

Projected report rows and metadata describing the exact output columns.

#
FieldTypePresenceNullableClassificationDescriptionExample
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"}

Recognition 9 schemas

Schema · 6 fields

RecognitionShoutOutQuery

Query parameters for listing shout-outs.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 6 fields

RecognitionShoutOutCreateRequest

JSON body for sending a shout-out. Unknown fields answer 422 unknown_field; nothing is saved unless every check passes.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

RecognitionShoutOutListResponse

Shout-outs, as listed or as just sent.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 7 fields

RecognitionPointsResponse

Points balances per employee. Points have no cash value; rewards with cash value go through payroll.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 10 fields

RecognitionBadgesResponse

The badge catalog, or one employee's progress when employee_id is given.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 10 fields

RecognitionRewardsResponse

The company's rewards store.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 8 fields

RecognitionRedemptionsResponse

Reward requests and managers' decisions.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 2 fields

RecognitionValuesResponse

What a shout-out can recognize.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

RecognitionShoutOutCreatedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Recruiting 9 schemas

Schema · 3 fields

RecruitingJobListQuery

Optional filters and cursor for GET /api/v1/jobs.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 20 fields

RecruitingJobListResponse

Job openings, oldest ID first.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 5 fields

RecruitingApplicantListQuery

Optional filters and cursor for GET /api/v1/applicants.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 35 fields

RecruitingApplicantListResponse

Applicants, oldest ID first. Details appear only with applicants.sensitive:read.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 39 fields

RecruitingApplicantResponse

One applicant, as returned by the retrieve, add and update endpoints.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 7 fields

RecruitingApplicantCreateRequest

JSON body for POST /api/v1/applicants. Any other field answers 422 unknown_field.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 4 fields

RecruitingApplicantUpdateRequest

JSON body for PATCH /api/v1/applicants/{applicant_id}. Send a stage, a note, or both.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 16 fields

RecruitingApplicantCreatedWebhookPayload

Payload for recruiting.applicant.created. Only the basic applicant record: never screening answers, resumes, notes or EEO answers.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 19 fields

RecruitingApplicantStageWebhookPayload

Payload for recruiting.applicant.stage_changed and recruiting.applicant.hired.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Communication 9 schemas

Schema · 4 fields

AnnouncementListQuery

Query parameters for GET /api/v1/announcements.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 21 fields

AnnouncementCollectionResponse

A page of announcements.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 17 fields

AnnouncementResponse

One announcement.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 8 fields

AnnouncementCreateRequest

JSON body for POST /api/v1/announcements. Any other field answers 422 unknown_field.

#
FieldTypePresenceNullableClassificationDescriptionExample
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"]
Schema · 20 fields

AnnouncementCreateResponse

The posted announcement (HTTP 201) and how it will be sent.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 3 fields

SurveyListQuery

Query parameters for GET /api/v1/surveys.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 13 fields

SurveyCollectionResponse

A page of surveys with participation counts.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 16 fields

SurveyResultsResponse

A survey's results as counts only. Never who answered, one person's answers, or written answers.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 4 fields

AnnouncementPublishedWebhookPayload

Payload produced when an announcement is posted on the Announcements page or through the API.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Onboarding 4 schemas

Schema · 10 fields

OnboardingCompletedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 26 fields

OnboardingHire

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 42 fields

OnboardingHireDetail

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 10 fields

OnboardingStartedWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Training 1 schema

Schema · 17 fields

TrainingWebhookPayload

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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}

Home care 2 schemas

Schema · 6 fields

HomeCareVisitQuery

Date range, filters and paging for home care visits.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 33 fields

HomeCareVisitCollectionResponse

Home care visits in visit ID order. No client details: the label is always "Home visit" and the client is an opaque reference.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Operations 8 schemas

Schema · 9 fields

OperationsWorkOrderListQuery

Query parameters for listing work orders. All are optional.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 11 fields

OperationsDateRangeQuery

Query parameters shared by the checklist, incident and tip declaration lists. Without from, to or updated_since, the last 30 days are returned.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 13 fields

OperationsWorkOrderCreateRequest

JSON body for creating a work order. Unknown fields answer 422 unknown_field; each invalid field answers 422 invalid_<field>.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 28 fields

OperationsWorkOrder

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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}. []
Schema · 25 fields

OperationsChecklistRun

One checklist run. Lists return data as an array of these; the single-record endpoint adds items.

#
FieldTypePresenceNullableClassificationDescriptionExample
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}. [...]
Schema · 21 fields

OperationsIncident

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.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 14 fields

OperationsTipDeclaration

Cash tips one employee declared for one shift or day. Needs operations.sensitive:read, which only an administrator can grant.

#
FieldTypePresenceNullableClassificationDescriptionExample
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
Schema · 4 fields

OperationsWorkOrderWebhookPayload

Payload of operations.work_order.created and operations.work_order.completed: the work order as the API lists it, and who acted.

#
FieldTypePresenceNullableClassificationDescriptionExample
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

Shared 2 schemas

Schema · 7 fields

WebhookEnvelope

JSON object delivered for every webhook event. The payload shape is selected by event, while the envelope remains stable.

#
FieldTypePresenceNullableClassificationDescriptionExample
id integer Required No Standard Tenant event-outbox ID. Use the delivery header, not this ID, to deduplicate individual delivery attempts. 9821
event string Required No Standard Event name used by webhook filters and the X-AppyShift-Event header. schedule.published
portal_slug string Required No Standard Company tenant that produced the event. acme
aggregate_type string Required Yes Standard Resource family associated with the event, when available. schedule_week
aggregate_id string Required Yes Standard String form of the associated resource identifier, when available. 2026-08-17
payload object Required No Conditional Event-specific payload. See the payload schema linked from the event catalog. {...}
created_at date-time Required No Standard Database timestamp recorded when AppyShift accepted the event. 2026-08-19 14:42:10
Schema · 3 fields

ApiError

Error envelope returned by protected API resources.

#
FieldTypePresenceNullableClassificationDescriptionExample
error.code string Required No Standard Stable machine-readable error code. missing_scope
error.message string Required No Standard Human-readable explanation safe to log. API token does not include the required scope.
error.request_id string Required No Standard Correlation ID for support and access-log lookup. req_xxx

Field formats

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 typeFormat valuesExample
Employee namedefault, legal, last_first, preferred, initialsLee, Jordan
Datedefault, iso, us, european, long, month_day05/01/2026
Phonedefault, formatted, digits(555) 123-4567
Numberdefault, number, currency$1,234.50
Checkboxdefault, checkmarkYes

Scopes

Scopes are assigned to the OAuth client and can be narrowed again when requesting a token.

ScopeAccessClassification
employee_fields:readList reportable employee field definitions and formats.Standard
employee_fields:writePartially update API-exposed custom field values.Standard
employee_fields.sensitive:writeUpdate custom fields classified as sensitive.Admin grant only
reports:readList report datasets and saved report definitions.Standard
reports:runRun saved and ad-hoc reports.Standard
reports.sensitive:readInclude compensation, birth date, address, and other sensitive HR fields.Admin grant only
employees:readRead the standard employee roster endpoint.Standard
employees:writeUpdate an employee payroll ID through the existing endpoint.Standard
credentials:readRead employee certifications and licenses.Standard
timesheets:readRead individual time entries.Standard
schedules:readRead scheduled shifts.Standard
departments:readRead departments and employee counts.Standard
positions:readRead positions and employee counts.Standard
locations:readRead work locations.Standard
time_off:readRead time-off requests and balances.Standard
deductions:readRead active employee deductions and employer matching amounts.Admin grant only
payroll:readRead payroll runs and company totals, tax liabilities and deposits, and the payroll general ledger (companies with payroll on)Standard
payroll.statements:readRead each employee's pay statements on payroll runs: earnings, deductions, taxes and net pay (administrator grant only)Admin grant only
recognition:readRead shout-outs, points balances, badges, rewards and reward requests (Recognition)Standard
recognition:writeSend shout-outs, with points from a sender's monthly bank or the company's awards (Recognition)Standard
recruiting:readRead job openings and applicants (name, email, phone, stage, source and dates)Standard
recruiting:writeAdd applicants from a job board or form, move their stage and add notesStandard
applicants.sensitive:readInclude applicant details: screening answers, cover letter, resume file details, notes, rating and the not-selected reasonAdmin grant only
announcements:readRead announcements with their audience, dates and acknowledgement countsStandard
announcements:writePost announcements to everyone or one department, optionally by push and emailStandard
surveys:readRead surveys and their results as counts (never who answered or written answers)Standard
onboarding:readRead new hires' onboarding progress, Form I-9 status and e-signature status (titles, statuses and dates only)Standard
visits:readRead home care visits for payroll and billing reconciliation (times, caregiver, status, mileage; never client names, addresses or notes)Standard
operations:readRead Operations work orders, checklist runs and incidents (only the sections the company has turned on)Standard
operations:writeCreate Operations work orders from an external systemStandard
operations.sensitive:readRead cash tip declarations: what each employee declared per day (administrator grant only)Admin grant only
Sensitive reporting

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.

Errors

Protected resource errors include a stable code, a readable message, and a request ID that can be matched to AppyShift access logs.

Error response
{
  "error": {
    "code": "missing_scope",
    "message": "API token does not include the required scope.",
    "request_id": "req_xxx"
  }
}
StatusCodeMeaning
400invalid_jsonThe JSON request body could not be parsed.
400invalid_scopeThe token request asked for a scope the client was not granted.
401invalid_clientThe OAuth client credentials were rejected.
401invalid_bearer_tokenThe access token is missing, expired, invalid, or revoked.
403missing_scopeThe token does not have the scope required by the endpoint.
404report_not_foundThe requested saved report does not exist in this company.
413request_too_largeThe report request body exceeded 256 KB.
422invalid_datasetThe requested report dataset is unavailable.
422invalid_viewThe selected resource view is not supported.
422invalid_metadataReport metadata is not a valid bounded flat key/value object.
422invalid_custom_fieldA custom field is inactive, non-reportable, unknown, or malformed.
422invalid_custom_field_valueA custom field value does not match its configured type or options.
429rate_limitedThe client or IP exceeded the current request limit.

Versioning

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.

  • Access tokens are short-lived and should be refreshed through the token endpoint.
  • Client secrets should never be embedded in browser or mobile application code.
  • Legacy aps_live_ keys remain supported for existing integrations, but new clients should use OAuth.