Skip to documentation
AppyShift logo

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}
18
Documented endpoints
15
Webhook events
46
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.

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}
}
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"]
  }
}
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/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/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}
}
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}
}
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/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"
    }
  }
}

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

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

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

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.

46 schemas
Schema

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

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

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

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

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

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

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

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

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

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

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

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

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

EmployeeFilterQuery

#

Optional filter used by employee-associated collection feeds.

FieldTypePresenceNullableClassificationDescriptionExample
employee_id integer Optional No Standard Return rows for one employee. 42
Schema

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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"}
Schema

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

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"}
Schema

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

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

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

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

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

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

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

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

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
Schema

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

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

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

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
Schema

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