# Account Setup and API Keys
Source: https://docs.zeal.com/docs/account-setup-and-api-keys
Zeal offers a full integration team to help you get up and running with our product. Although our team leads this process, in this guide we give you an overview of the steps to set up your account.
If you haven’t already, [contact Zeal](https://www.zeal.com/request-a-demo?referrer=%2F) to create a Zeal Partner Account.
## In this guide
* How to access the Partner Dashboard and invite your team members.
* How to configure your white-label components.
* Where to manage your API keys.
* How to set up your webhooks.
***
## Partner Dashboard
Once our team creates your account, you can access your Partner Dashboard at [app.zeal.com](https://app.zeal.com).
### Logging in for the first time
If it’s your first time logging in, click the **Forgot Password** link and follow the steps to create a new password.
From your Partner Dashboard, you can manage all your settings as well as oversee your users (employers and workers on your payroll system).
### Quickstart
Of course, when you first begin, you have no users. You can reference our [Quickstart Guide](/docs/quickstart-guide) to get started.
### Inviting team members
To add other team members, navigate to the **Members** page and click the **Invite new members** button.
***
## White-label configuration
If you plan on using any of Zeal’s white-label components, you want to ensure that everything is branded as your own. To do this you:
1. Configure the domain for the components
2. Set your base URL
3. Brand the components with your logo and favicon
### Configuring your domain
Our integration team sets up your white-label components to point to your desired domain. That way, your URL displays on all the white-label components. Often, our partners choose a subdomain such as *payroll.\[your-domain].com*. Our integration team also assists with your DNS settings.
Typically, the instructions to set up a custom URL for white-label components are as follows:
1. Provide Zeal with your desired subdomain (e.g., payroll.yourcompany.com).
2. You'll receive two CNAME records from Zeal:
1. First CNAME: Set this record as provided by Zeal.
2. Second CNAME: Point your subdomain to app.zeal.com.
3. Add both CNAME records to your domain's DNS settings.
3. Wait for Zeal to complete the backend setup. Once Zeal confirms setup is complete, your white-labeled payroll app should be accessible at your chosen subdomain.
### Setting your base URL
Whenever a user completes an onboarding flow or logs out of a white-label component, you want them to return to a familiar place. For Zeal to know where to redirect your users, you configure a base URL.
Under the **Settings** page, click the **Edit** button under the **Branding** tab.
Then, scroll to the **Base URL** field, enter your desired URL, and click **Save changes**.
### Adding your branding
Finally, to brand the white-label components as your own, you can add your logo and favicon (the icon that appears in the browser tab above the URL).
Navigate to the **Settings** page, click on the **Branding** tab, then click the **Edit** button.
Next, click **Select file** and upload images for the logo and favicon respectively. Then click **Save changes.**
With all the configuration set, the white-label components now are on your domain and branded as your own. Whenever a user navigates away from the component, they are redirected to your site.
***
## API keys
Zeal’s APIs all require an API key for standard bearer token authentication. Additionally, some endpoints may require a `partnerID` in your request. All of these credentials can be found under the **API** page of the Partner Dashboard.
### Production versus Test keys
It's important to note the *Production API key* affects *production* resources; payroll is run, money is disbursed, etc. *The Test API key* affects *test* resources; payroll is processed similarly, but without money being disbursed or other real side effects. You should use the Test API key for development and only use the Production API key when deploying your live payroll solution.
### Rolling a key
You should treat API keys as you would any other password; grant access only to those who need it and ensure keys don't enter any version control system.
If a key is compromised, you can roll the key from the API page. Simply click the refresh icon next to the key and follow the prompts.
***
## Webhooks
Webhooks allow you to programmatically *hook* into events. An event could be a user changing data through a white-label component or an *asynchronous* process (something that happens outside of direct interaction with our APIs, such as the processing of Employer Checks). Zeal sends data about events to their corresponding webhook URL configured in your settings.
### Setting a webhook URL
Under the **API** page, are tabs for each webhook event Zeal supports. To set a webhook URL for an event, click on its corresponding tab, paste your URL in the input field, and click **Update**.
You can test that the webhook is configured correctly by clicking the **Test** button. This sends a default payload to the webhook URL.
### Adding security
Zeal always includes a webhook secret in the header of each payload sent to your system. You can find this secret under the **Webhook secrets** tab on the **API page**.
To add a layer of security, you should configure your endpoints (webhook URLs) to only accept requests which include a `Puzzl-Signature` header with this secret.
***
## Recap
* You can manage all your settings and oversee your users from the Partner Dashboard.
* On the **Members** page you can invite your team members to the dashboard.
* To brand your white-label components: configure your domain, add your base URL, and upload your logo and favicon.
* Production and Test API keys are accessed or rolled from the API page.
* Webhooks are also configured from the API page.
# Accrual Policies
Source: https://docs.zeal.com/docs/accrual-policies
Learn how to set up and manage a PTO or Sick Time Policy for your workers
## Intro
Offering a a PTO or sick time policy is a good way to attract a great workforce and can be critical for employer compliance. Managing these policies, however, involves proper accrual rates, PTO usages, capping PTO balances, rollovers, etc.
In Zeal, Accrual Policies represent policies that can be accrued by and assigned to workers. These Accrual Policies, when attached to a worker, contain an accrual balance that is automatically tracked and updated by Zeal based on the worker's shifts as well as their specific Accrual Policy specifications.
## In this guide
* What an accrual policy is
* How to set up a standard policy
* How to add employees to a policy
* How to track usages that affect the balance (e.g. PTO usage)
* How to handle more complex rules
## What is an accrual policy?
An accrual policy is simply a set of rules that define how employees accrue hours for various perks such as PTO or sick leave. The basic rules generally state the rate of accrual and the number of hours that must be worked before that rate is accrued (e.g. an employee earns 5 hours for every 80 hours worked). The policy may also include more complicated rules such as annual caps, wait periods, and rollover rules.
## Managing a standard PTO policy
Let’s start with a basic accrual policy. We’ll define a PTO policy where employees accrue 5 hours off for every 80 hours worked.
### Step 1: Create the policy
To create an Accrual Policy, utilize the [Create Accrual Policy](/reference/embedded-hr/create-accrual-policy) or POST `/accrualPolicy` endpoint. The endpoint requires the following body parameters:
* `companyID`: Zeal Company ID
* `policy_code`: Custom code you must assign for the policy. **This is the unique identifier for the policy**
* `policy_type`: Type of the accrual policy (accepts: pto, sick\_leave, or custom). *Note*: The accrual policy type has no effects on other parameters other than classification of the accrual policy. Therefore, a `pto` policy type does not differ from a `sick_leave` type other than in classification.
#### Other parameters:
As mentioned in the Accrual Policy object reference, the POST endpoint accepts other body parameters to further specify the Accrual Policy being created:
| attribute | type | description |
| ------------------------ | ---------- | --------------------------------------------------------------------------------------------------------- |
| policy\_name | string | Custom name that can be assigned for the policy |
| policy\_effective\_date | YYYY-MM-DD | The effective start date of the policy |
| accrual\_rate\_hours | float | The rate at which employees will accrue hours |
| accrual\_period\_hours | float | The number of hours employees need to work to accrue accrual\_rate\_hours |
| immediate\_balance | float | The immediate hour balance the employee would receive |
| include\_doubletime | boolean | Include if double-time work is eligible for hour accrual |
| include\_overtime | boolean | Include if overtime work is eligible for hour accrual |
| accrual\_waiting\_period | float | The number of hours the employees need to work before they are eligible to begin accruing time for policy |
| accrual\_cap | float | Max hours an employee can accrue in one year until the rollover date |
| rollover\_cap | float | Max hours an employee can rollover from one year to the next year, on a specified rollover date |
| rollover\_date | float | Required if the user passes a value for `rollover_cap` or `accrual_cap` |
Let’s create a PTO policy with an accrual rate of 5 hours for every 80 hours worked. We will set`accrual_rate_hours` at `5` and `accrual_period_hours` to `80`.
[Create accrual policy](/reference/embedded-hr/create-accrual-policy)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/accrualPolicy \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"policy_code": "PTO-01",
"policy_type": "pto",
"accrual_rate_hours": "5",
"accrual_period_hours": "80",
"include_doubletime": false,
"include_overtime": false,
}
'
```
This will return an [Accrual Policy object](/reference/embedded-hr/accrual-policy-object):
```bash bash theme={null}
{
"companyID": "e9a3c22ea5276a1ea82dba27ca6e1a2ea",
"policy_code": "PTO-01",
"policy_type": "pto",
"policy_name": null,
"policy_effective_date": "2023-03-01",
"accrual_rate_hours": 5,
"accrual_period_hours": 80,
"immediate_balance": 0,
"include_doubletime": false,
"include_overtime": false,
"accrual_waiting_period": 0,
"accrual_cap": 0,
"rollover_cap": 0,
"rollover_date": null,
"policy_status": "live"
}
```
### Step 2: Add employees
With the policy created, next we add our employees to the policy.
[Add/remove employees to accrual policy](/reference/embedded-hr/add-employees-to-accrual-policy)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/accrualPolicyEmployees \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"add_employees": [
"{{firstEmployeeID}}",
"{{secondEmployeeID}}",
"{{thirdEmployeeID}}"
],
"companyID": "{{companyID}}",
"policy_code": "PTO-01"
}
'
```
All the employees added will now automatically begin accruing hours based on the payroll hours submitted.
### Step 3: Get accrual balance
We can get the balance of an employee at any time.
[Get accrual balance](/reference/embedded-hr/get-accrual-balance)
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/accrualBalance?companyID={{companyID}}&employeeID={{employeeID}}' \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json'
```
This will give us a response detailing the policy and the hours the employee has under that policy.
```bash bash theme={null}
{
"success": true,
"data": {
"companyID": "{{companyID}}",
"accrualPolicies": [
{
"policy_code": "PTO-01",
"employeeID": "{{employeeID}}",
"policy_type": "pto",
"accrual_balance": 20,
"accrual_rate_unit": "hours",
"policy_status": "live"
}
]
}
}
```
### Step 4: Apply accrual usage
When an employee requests off and completes it, we can apply usage, which affects the employee's balance. Let's say our employee takes 16 hours off (from their previous balance of 20hrs).
[Apply accrual usage](/reference/embedded-hr/create-accrual-policy-usage#/)
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/accrualPolicy/{{policyCode}}/usage \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"employees": [
{
"employeeID": "66c7738bbabb2213d7628c02",
"start_date": "2024-12-10",
"end_date": "2024-12-12",
"amount": 16
}
],
"companyID": "{{companyID}}"
}
'
```
Now the employee's balance is updated to 4 hours of PTO. They continue to accrue hours automatically as they work. The next time the employee completes a PTO request, we simply repeat step 4.
**Here are a few important notes:**
1. The accrual policy that you are referencing as a path parameter (using policyCode) in this request must have a valid `policy_effective_date`.
2. The employee must already be added to the accrual policy in order for you to assign usage for this employee and under this accrual policy.
3. Zeal finds an employee check for this employee with the reporting period that encapsulates the `start_date` of the usage object.
1. For example, if an employee check was created for Jim with reporting period January 6th - January 13th and an accrual usage was set with `start_date` January 8th and `end_date` January 15th, (Jan 8th-Jan 15th), then Zeal will attach the usage to this check because the `start_date` falls within the reporting period of that check.
2. If there is no existing check for this employee with a reporting period that encapsulates the `start_date`, then you will get an error (`No check for given date range`)
4. Usage will also show on the paystub of an existing employee check with a reporting period that encompasses the `start_date` of the usage object.
5. It is possible for the accrual balance to be negative for an employee, if using usage.
#### Corrections to Usage
In case you misapplied usage, you can make a similar call to adjust the usage and balance.
Let's say instead of using 16 hours, this worker actually only used 14 hours. You can apply a correction of 2 hours, reducing the employee's usage within the same date range used above:
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/accrualPolicy/{{policyCode}}/usage \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"employees": [
{
"employeeID": "66c7738bbabb2213d7628c02",
"start_date": "2024-12-10",
"end_date": "2024-12-12",
"correction": true,
"amount": 2
}
],
"companyID": "{{companyID}}"
}
'
```
After this request is applied, the total usage for the employee within the specified date range would be calculated to 14 (instead of 16 previously).
## Handling more complex cases
Many accrual policies have additional rules such as annual caps, waiting periods, and rollovers. Thankfully, Zeal's system manages these complexities with ease.
### Setting an annual cap
It's common to set a cap on the number of hours that can be accrued in one year. If you have such a policy in place, all you have to do is tell Zeal the cap, and the system will stop adding to an employee's balance once they've hit the annual limit. Let's update our policy with an `accrual_cap` set to `100` hours.
[Update accrual policy](/reference/embedded-hr/update-accrual-policy)
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/accrualPolicy \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"policy_code": "PTO-01",
"accrual_cap": 100
}
'
```
Now our employee's are only able to accrue up to 100 hours of PTO within a calendar year. At midnight on the first day of the year, the cap resets and employees resume accruing hours.
### Setting a waiting period
Many policies define a waiting period, or cliff, that an employee must meet before they can begin accruing hours. This is generally used to prevent new hires from immediately taking time off. Let's update our policy with a `accrual_waiting_period` of `160` hours.
[Update accrual policy](/reference/embedded-hr/update-accrual-policy)
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/accrualPolicy \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"policy_code": "PTO-01",
"accrual_waiting_period": 160
}
'
```
Now our employees must work 160 hours before they are able to begin accruing PTO.
### Setting rollover rules
Rollover rules define how many hours an employee can keep, or rollover, into the next year. These rules generally set a cap on hours and a date that the rollover happens. On the given date, any hours an employee has accrued *above* the cap are forfeited. This encourages employees to use their time off for rest and recuperation. Let's update our policy with a `rollover_cap` of `60` hours and the `rollover_date` of `01-01` (Jan. 1st).
[Update accrual policy](/reference/embedded-hr/update-accrual-policy)
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/accrualPolicy \
--header 'Authorization: Bearer {{TEST_API_KEY}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"policy_code": "PTO-01",
"rollover_cap": 60,
"rollover_date": "01-01"
}
'
```
Now with our rollover rules in place, employees can only carry up to 60 hours of PTO into the next calendar year. **Note:** many policies set the rollover date to the first day of the year, but you can set the date to whatever works for your policy.
## Recap
* An accrual policy is simply a set of rules that define how employees accrue hours for various perks such as PTO or sick leave
* Managing accruals with Zeal generally involves 4 steps: *create an accrual policy*, *add employees to the policy*, *query for accrual balances*, *apply usage when employees take time off*
* Zeal's system accounts for complex rules such as *annual caps*, *waiting periods*, and *rollovers*
# Company Dashboard
Source: https://docs.zeal.com/docs/admin-employer-dashboard-guides
An essential piece of your payroll product is the Company Dashboard. In this guide we’ll show how to build a custom dashboard through APIs and how to offer it out-of-the-box with our white-label components.
## In this guide
* Which endpoints are needed to recreate the Company Dashboard.
* How to embed the white-label Company Dashboard in your application.
***
## API
Since a custom Company Dashboard can take so many forms, we'll focus on providing an overview of the endpoints we recommend using rather than giving detailed code examples. We’ll use Zeal’s white-label component to provide an example structure for your dashboard.
### Home Page
1. Use [Get All Company Checks](/reference-link/retrieve-all-employer-checks) or [Get Employer Checks by Dates](/reference-link/retrieve-employer-checks-by-dates) and get the data from the most recent Employer Check to display the *Last payroll run* and *Upcoming payroll run* sections.
2. Use [Get Employees](/reference/employees/get-employees) and [Get Contractors](/reference/contractors/get-contractors) and filter by `onboarded` status and `start_date` to display *Recently onboarded workers*.
### People Page
1. Use [Get Employees](/reference/employees/get-employees) and [Get Contractors](/reference/contractors/get-contractors) to display all workers.
2. Use [Create Employee](/reference/employees/create-employee) and [Create Contractor](/reference/contractors/create-contractor) to provide a form to create workers.
3. Use [Get Employee Onboarding Link](/reference/employee-onboarding/generate-employee-onboarding-link) and [Get Contractor Onboarding Link](/reference/contractor-onboarding/generate-contractor-onboarding-link) to allow for onboarding employees and contractors.
### Tip
You might also choose to build your own custom onboarding flow. Please reference our [Employee Onboarding](/docs/employee-onboarding-guide) and [Contractor Onboarding](/docs/contractor-onboarding-guide) guides for more information.
### Individual Worker Page
1. Use [Get/Update Employee Information](/reference/employees/get-employee-information) and [Get/Update Contractor Information](/reference/contractors/get-contractor-information) to allow companies to view/edit the personal and employment information of their workers.
2. Use [Get Bank Account by Employee/Contractor ID](/reference/bank-accounts/get-bank-accounts-by-worker-id) to display bank information. Use [Update Bank Account](/reference/bank-accounts/update-bank-account) to allow companies to correct bank account information.
3. For employees, use [Get Employee Tax Parameter Summary](/reference/employee-onboarding/get-employee-tax-parameter-summary) and [Set Employee Tax Parameters](/reference/employee-onboarding/set-employee-tax-parameters) to allow companies to view/edit the employee's tax information.
### Work Locations
1. Use [Get Work Locations](/reference/work-locations/get-work-locations) to display Work Locations.
2. Use [Resolve Taxable Location](/reference/taxable-locations/resolve-taxable-location) to verify a taxable address and then [Create Work Location](/reference/work-locations/create-work-location) to add new locations.
### Tip
Check out our [Work Locations Guide](/docs/work-locations-guide) for more details.
### Pay Page
1. Use [Create Employee Check](/reference/employee-checks/employee-checks/create-employee-check) and [Create Contractor Payment](/reference/contractor-payments/create-contractor-payment) to allow for creation of payroll.
2. Use [Get Employee Check by ID](/reference/employee-checks/employee-checks/get-employee-check-by-id) and [Get Contractor Payment by ID](/reference/contractor-payments/get-contractor-payments) to display details about a particular check or payment.
3. Use [Get Employer Checks by Dates](/reference-link/retrieve-employer-checks-by-dates) to show the recent payroll history and [Get Employer Check by ID](/reference/employer-checks/get-employer-check-by-id) to display details of a particular payroll run.
### Tax Setup Page
Our partners generally choose to embed our out-of-the-box tax component so that companies can submit important tax documents directly. Use [Generate Company Taxes Page link](/reference/zeal-components/generate-company-taxes-page-link) and embed the component directly in your custom dashboard.
### Reports Page
Similar to the Tax Setup page, most partners generally use Zeal's out-of-the-box Report Page component in their custom dashboards. Use [Get Reports Link](/reference/zeal-components/generate-reports-link) and embed the component directly in your custom dashboard.
***
## White-Label
1. The company logs in to your application.
2. Once they are authenticated, call [Generate Company Login Link](/reference/zeal-components/generate-company-login-link) to get an SSO link specific to this company that they can use to access the dashboard without having to log in again.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/getAuthLink'
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testApiKey}}'
--data-raw '{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}"
}'
```
3. Give the company access to the link. Generally our partners include the link in their application or display the component directly through an iframe.
```bash bash theme={null}
Click to access your payroll dashboard!
```
4. When the company accesses the link, they’ll see the white-label component (on your domain with your logo) where they can manage people, payroll, and their information.
***
## Recap
* The Company Dashboard provides core functionality to your users such as running payroll and managing workers.
* All the data and processes needed to build your customer company dashboard are exposed through Zeal's API endpoints.
* You may embed the white-label Company Dashboard directly in your application.
# Building a Payroll Product
Source: https://docs.zeal.com/docs/building-a-payroll-product
Building a payroll product can seem daunting at first, especially if you don’t come from a payroll background. At Zeal, our team of payroll experts is here to help. In this guide, we'll walk you through everything you should know to offer payroll, confidently.
## In this guide
* What the 4 core components of a payroll product are.
* What should be included in employer onboarding.
* What should be included in worker onboarding.
* What should be included in the employer dashboard.
* What should be included in the worker dashboard.
***
## Four core components of a payroll product
If you examine payroll products on the market, they generally consist of 4 core components or flows: **Employer** **onboarding**, **worker onboarding**, **an employer dashboard**, and **a worker dashboard**. With Zeal, you can easily build these key flows using our white-label components and/or APIs.
### Employer onboarding
Onboarding employers is a key flow for any payroll platform. Employers must submit basic company information, bank account details, and legal paperwork. Zeal uses this information to manage compliance, run payroll, and remit and file taxes on behalf of the employer.
If you’re a staffing or EOR Partner, building an internal payroll solution, then you are also the employer. In this case, you can access the employer onboarding flow directly from the Partner Dashboard. There’s no real need to add this flow to your application.
If you’re a vertical SaaS or reseller Partner, you want to white-label the employer onboarding flow. You can do this using the Company Onboarding component or Company Onboarding APIs.
See [Employer Onboarding](/docs/employer-onboarding-guide) for more information.
## Worker onboarding
The next key component of your payroll solution is worker onboarding. Workers need a flow to submit their basic information, bank details, and tax documents. Zeal uses this information to run payroll and process end-of-year W-2 and 1099 forms for workers.
Many of our Partners who have a worker app or plan to build one, often integrate with Zeal’s Employee Onboarding API and Contractor Onboarding API or embed our white-label onboarding components directly into their app. However, many of our reseller Partners, do not offer a worker app directly and prefer to focus only on the employer experience. In these cases, worker onboarding can be initiated through email, directly from the Employer Dashboard.
See [Worker Onboarding](/docs/worker-onboarding-guides) for more information.
## Employer dashboard
An employer dashboard offers key functionality for the payroll system. Payroll admins managed processes such as onboarding workers, running payroll, and submitting tax requirements form an employer dashboard . Zeal offers an out-of-the-box white-labeled Employer Dashboard which provides all of these features and more. You may also choose to use Zeal’s APIs to integrate these features into an existing user dashboard for a more native feel.
See [Employer Dashboard](/docs/admin-employer-dashboard-guides) for more information.
## Worker Dashboard
A worker dashboard offers workers access to payroll. From the worker dashboard, workers should be able to view and download paystubs, edit their personal and tax information, and access end-of-year documents such as 1099 and W-2 forms. Zeal offers out-of-the-box white-labeled Employee Dashboards and Contractor Dashboards which provide all of these features and more. You may also choose to use Zeal’s APIs to integrate these features into an existing user dashboard for a more native feel.
See [Worker Dashboard](/docs/worker-dashboards-guides) for more information.
***
## Recap
* Payroll products generally are made up of four core components: **Employer onboarding**, **worker onboarding**, **an employer dashboard**, and **a worker dashboard**.
* A employer onboarding flow allows employers to submit necessary payroll data such as business information, bank details, and legal paperwork.
* A worker onboarding flow allows workers to submit personal information, bank details, and tax parameters.
* A employer dashboard provides core functionality to payroll admins such as onboarding workers, running payroll, and submitting tax requirements.
* A worker dashboard provides core functionality to workers such as accessing pay stubs and documents and editing personal information.
# Contractor Dashboard
Source: https://docs.zeal.com/docs/contractor-dashboard-guide
Contractors need a space to view their profile information and payment history as well as access their 1099 form and other tax information. You can provide this out-of-the-box with the white-label component or build a custom dashboard using our API.
## In this guide
* The endpoints needed to recreate the Contractor Dashboard.
* How to embed the white-label Contractor Dashboard in your application.
***
## API
We’ll use **Zeal’s white-labeled Contractor Dashboard** as a reference for our custom dashboard.
### How to build a Home Page
1. Call [Get Contractor Payments by Contractor](/reference/contractor-payments/get-contractor-payments).
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/contractorPayments?companyID={{companyID}}&contractorID={{contractorID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
```
2. Call [Get Contractor Payment by ID](/reference/contractor-payments/get-contractor-payments) to show details of a particular payment.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/contractorPayment?companyID={{companyID}}&contractorPaymentID={{contractorPaymentID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
```
### How to build a Profile Page
1. Use [Get/Update Contractor Information](/reference/contractors/get-contractor-information) to allow the contractor to view/edit their profile information.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/contractors?companyID={{companyID}}&contractorID={{contractorID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
2. Call [Get Bank Account by Employee/Contractor ID](/reference/bank-accounts/get-bank-accounts-by-worker-id) to get information about a contractor's bank account. Use [Update Bank Account](/reference/bank-accounts/update-bank-account) to allow the contractor to correct their bank information.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/bankaccount?companyID={{companyID}}&id={{contractorID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
### How to build a Contractor Documents section
Call [Get Documents](/reference/documents/get-documents) to retrieve a list of employee documents such as 1099s or 1099 Cs.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/documents?companyID={{companyID}}&id={{contractorID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
***
## White-Label
There are two ways to allow a Contractor to access their dashboard.
### SSO Link
1. If you’ve already authenticated the contractor on your system, call [Generate Contractor Dashboard Link](/reference/zeal-components/generate-employee-contractor-dashboard-link) to get an SSO link directly to the contractor's dashboard.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/getAuthLink'
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json'
--data-raw '
{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}",
"contractorID": "{{contractorID}}"
}
'
```
2. Now, allow the contractor to access the link or embed the component directly in your application through an iframe .
```bash bash theme={null}
Click to begin payroll onboarding!
```
### Login Credentials
1. During the [Contractor Onboarding](/docs/contractor-onboarding-guide), include the account creation step by setting `"contractor_acct": true`
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/contractors/onboard \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"profile": true,
"contractor_acct": true
}
'
```
2. The contractor creates credentials that they can use to log into their contractor dashboard.
3. The contractor navigates to your domain (e.g. payroll.\[your-domain].com) and inputs their credentials to log in.
***
## Recap
* The Contractor Dashboard provides core functionality to your payroll products such as allowing users to access paystubs and personal information.
* All the data and processes needed to build your customer contractor dashboard are exposed through Zeal's API endpoints.
* You may embed the white-label Contractor Dashboard directly in your application.
# Contractor Onboarding
Source: https://docs.zeal.com/docs/contractor-onboarding-guide
1099 Contractors can be onboarded to the payroll solution via the API or white-label components. Since companies aren’t responsible for paying taxes on or withholding taxes from a contractor’s pay, much less information needs to be collected to onboard a contractor than a W-2 Employee.
## In this guide
* How to create a Contractor
* How to submit a W-9 form
* How to add a contractor Bank Account
* How to onboard a contractor using white-label components
***
## API
### Create a Contractor
Call [Create Contractor](/reference/contractors/create-contractor).
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/contractors \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"new_contractors": [
{
"email": "[email protected]",
"first_name": "Monica",
"middle_name": "string",
"last_name": "Hall",
"type": "individual",
"ssn": "123456789",
"ein": "string",
"business_name": "string",
"address": "1 Market St.",
"city": "San Francisco",
"state": "CA",
"zip": "94110",
"onboarded": false
}
],
"companyID": "{{companyID}}"
}
'
```
### W9: Fetching Paperwork Templates
The W9 form can be sent to Zeal using the Paperwork endpoints.
The [Paperwork Template object](/reference/paperwork-api/paperwork-template-object) outlines the fields that represent a Paperwork Template, which includes key information such as the name of the form, the applicable jurisdiction(s), and the fields on the form. For the purposes of this guide, we will be focusing on Paperwork Templates with `paperwork_type` as `W9`.
Paperwork Templates can be fetched using the [Get Paperwork Template](/reference/paperwork-api/get-paperwork-templates). Be sure to include the jurisdiction(s) and the effective date for the W9 form you want to retrieve.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/paperwork/templates \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "fc235fcccee46aa8a082f357715bcfa",
"paperwork_type": "W9",
"worker_type": "Contractor",
"jurisdictions": {
"type": "include",
"jurisdictions": [
"US"
]
},
"jurisdiction_type": "WorkLocation",
"effective_date": "2024-07-01"
}
'
```
This will return the templateID for the W9 that you will need when creating a Submission. Here is an example response:
```bash bash theme={null}
{
"templates": [
{
"templateID": "form-479ae926-3a6c-4b72-956a-4fe569064215",
"form_name": "Federal W-9",
"paperwork_type": "W9",
"worker_type": "Contractor",
"jurisdictions_filter": {
"type": "include",
"jurisdictions": [
"US"
]
},
"jurisdiction_type": "WorkLocation",
"effective_date": "2022-01-01",
"archive_date": "",
"form_fields": [
{
"field_name": "signature_text",
"label": "Signature Text",
"error_text": "A signature is required",
"type": "base64",
"zeal_autofill": false,
"required": false,
"fieldName": "signature_text",
"x": 148.802,
"y": 229.07,
"width": 150.00000000000003,
"height": 22
},
{
"field_name": "type",
"label": "Contractor object autofill field",
"required": false,
"type": "string",
"zeal_autofill": true,
"fieldName": "type",
"x": 61.075,
"y": 618.384,
"width": 18,
"height": 18
},
{
"field_name": "first_name",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "last_name",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "ssn",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "address",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true,
"fieldName": "address",
"x": 185.615,
"y": 528.333,
"width": 150,
"height": 16.29600000000005
},
{
"field_name": "city",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "today_full",
"required": false,
"label": "Date autofill field",
"type": "string",
"zeal_autofill": true,
"fieldName": "today_full",
"x": 421.25,
"y": 229.11,
"width": 150,
"height": 22,
"_id": "66ad78fc79101a05d8c4e286"
},
{
"field_name": "start_date",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "business_ein",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "state",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "zip",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "middle_initial",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "business_name",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true,
"fieldName": "business_name",
"x": 90.6556,
"y": 661.36,
"width": 149.99939999999998,
"height": 15.480999999999995
},
{
"field_name": "business_city",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "business_address",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "business_state",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "business_zip",
"required": false,
"label": "Company object autofill field",
"type": "string",
"zeal_autofill": true
},
{
"field_name": "address_line2",
"required": false,
"label": "Contractor object autofill field",
"type": "string",
"zeal_autofill": true
}
],
"status": "Active",
"urls": []
}
]
}
```
Note that the Paperwork Template also includes a URL containing the form in case you want to show a worker what they are filling out.
### W9: Submitting Paperwork
To submit a completed W9 form, use the [Create Paperwork Submission](/reference/paperwork-api/create-paperwork-submission) or PUT `/paperwork/submissions` endpoint. The endpoint accepts the following body parameters:
* `templateID`: Unique identifier for the Paperwork Template (from previous step)
* `worker_type`: Type of worker (contractor)
* `companyID`: Unique identifier for the company
* `employeeID`: Unique identifier for the employee (nullable if the worker type is contractor)
* `contractorID`: Unique identifier for the contractor (nullable if the worker type is employee)
* `fields`: The completed fields and values
Below is a JSON body example of a PUT `/paperwork/submissions` request:
```bash bash theme={null}
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"worker_type": "contractor",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"contractorID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
}
}
```
This will save the completed W9 paperwork submission for this contractor.
### W9: Fetching Paperwork Submissions
You can always fetch the completed paperwork submission(s) using the [Get Paperwork Submissions](/reference/paperwork-api/get-paperwork-submissions) or POST `/paperwork/submissions` endpoint. The endpoint allows filtering by `paperwork_type`, `companyID`, `jurisdiction_filter`, and `worker_filter`.
Below is an example JSON response of a successful POST `/paperwork/submissions` request:
```bash bash theme={null}
{
"success": true,
"data": [
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"submissionID": "a1b2c3d4-e5f6-4a5b-8c7d-9e0f1a2b3c4d",
"submission_date": "2023-06-01T12:00:00Z",
"worker_type": "contractor",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"contractorID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
},
"paperwork_type": "W9",
"url": "https://example.com/submission/12345"
}
]
}
```
### Add a Bank Account (optional)
### Note
This is an optional step. A Contractor onboarded without a bank account can still be paid with any disbursement method other than `direct_deposit`.
Call [Create Bank Account](/reference/bank-accounts/create-bank-account) to create the contractor bank account.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/bankaccount \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"companyID": "{companyID}",
"id": "{{contractorID}}",
"institution_name": "Chase",
"account_number": "123456789",
"routing_number": "267084131",
"type": "checking"
}
'
```
### Set onboarded to true
Call [Set Onboarded Status to True](/reference/contractor-onboarding/set-onboarded-status-to-true).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/contractors/setOnboardedStatusToTrue \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"contractorID": "{{contractorID}}",
"companyID": "{{companyID}}"
}
'
```
With the onboarded status updated, the contractor is considered onboarded and can start receiving payments.
***
## White-Label
### Access the Company Dashboard
Navigate to your Partner Dashboard and ensure that *Test Mode* is enabled. Then, click on a Company to access the Company Dashboard as an Admin.
### Add a Contractor
Navigate to the **People** page, click the *Contractors* tab, then click **Add contractor** .
Fill the contractor information and click **Add Contractor**.
### Send the onboarding link
Back on the **People** page, find the Contractor and click **Copy onboarding link** then click **Send link to contractor's email**.
### Tip
The link can also be accessed programmatically by calling [Generate Contractor Onboarding Link](/reference/contractor-onboarding/generate-contractor-onboarding-link).
### Complete the onboarding flow
When the contractor navigates to the page, they see the white-label component on your domain with your logo.
The contractor completes the onboarding flow. You can view the information in the Company Dashboard.
### Note
When the Contractor Onboarding flow is completed successfully through the white-label, data about the Contractor is sent to the webhook established for the [Contractor Event Webhook](/reference/webhooks/contractor-event-webhook).
***
## Recap
* To onboard a contractor, personal information and a W-9 form should be collected
* Bank account details don't need to be submitted, but the contractor can't be paid by direct deposit without them
* Companies can create Contractors from the Company Dashboard
* Contractor can complete onboarding through the Contractor Onboarding component
# Contractor Payments
Source: https://docs.zeal.com/docs/contractor-payments-guide
Contractor payments are rather simple as there are no taxes for the employer to pay and the contractor is responsible for paying their own taxes.
## In this guide
* How to create a contractor payment through the API.
* How to create a contractor payment through the white-label Employer Dashboard.
***
## API
Call [Create Contractor Payment](/reference/contractor-payments/create-contractor-payment).
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/contractorPayment \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"approval_required": false,
"companyID": "{{companyID}}",
"contractorID": "{{contractorID}}",
"pay_date": "2022-01-15",
"amount": 2000,
}
'
```
With the Contractor Payment in the system, it will automatically be batched and processed by Zeal.
***
## White-Label
### Access the Company Dashboard
Navigate to your Partner Dashboard and ensure that **Test Mode** is enabled. Then, click on a company to access the Company Dashboard as an Admin.
### Create a Contractor Payment
Navigate to **Pay Contractors** and fill the details of the contractor payment and then click **Create Payment**.
With the Contractor Payment in the system, it will automatically be batched and processed by Zeal.
***
## Recap
* Contractor Payments are much simpler than Employee Checks and only really need an `amount` and `pay_date`.
* You can create a Contractor Payment with the [Create Contractor Payment](/reference/contractor-payments/create-contractor-payment) endpoint.
* You can create a Contractor Payment from the Company Dashboard.
* Once Contractor Payments are submitted, they will automatically be processed by Zeal.
# Custom Paperwork (Early Access)
Source: https://docs.zeal.com/docs/custom-paperwork
Learn how to create Custom Paperwork that can be used in worker onboarding.
## Intro
Custom Paperwork allows companies to create and manage various paperwork templates tailored to their specific needs. The Paperwork can then be used in the worker onboarding as needed. Zeal offers a powerful API to view these paperwork templates and create paperwork submissions.
## In this guide
* How to set up Custom Paperwork Templates in the UI
* Which endpoints are needed to manage Custom Paperwork templates
* Which endpoints are needed to create Paperwork submissions (coming soon)
* A step-by-step explanation on utilizing these endpoints
## Setting up Custom Paperwork Templates
### Company Dashboard
The first step for using Custom Paperwork is to create "Paperwork Templates". Templates can currently only be created in the "Paperwork" tab in the company dashboard via the Zeal application UI:
When you add Paperwork, you will be directed to:
1. Upload the file and paperwork metadata in the **Paperwork Details** page
2. Set the intended **Recipients**. Only these workers will be prompted to complete this paperwork by default in onboarding
3. Upload a file in the **Template Editor**. You may remove/add fields, set required/optional fields, and add signature requirements
4. **Review and Finish**
### API
Once the template is created in the UI, the template can be fetched via the API.
The [Paperwork Template object](/reference/paperwork-api/paperwork-template-object) outlines the fields that represent a Paperwork Template. Templates can only be created through the UI and are managed at the company level. Templates rely on several required attributes:
| attribute | type | description |
| --------------------- | ------ | -------------------------------------------------------------------- |
| templateID | string | Unique identifier for the template |
| form\_name | string | Name of the paperwork form |
| paperwork\_type | string | Type of paperwork (e.g. CustomPaperwork) |
| worker\_type | string | Type of worker for the template (Employee, Contractor, All) |
| jurisdictions\_filter | object | Filter for jurisdictions to include or exclude |
| jurisdiction\_type | string | Type of jurisdiction for the template (Worklocation, Residency, All) |
| effective\_date | string | Date from which the template is effective |
| archive\_date | string | Date when the template will be archived |
| form\_fields | array | Array of form fields present on this template |
Below is a JSON example of a Paperwork Template object:
```bash bash theme={null}
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"form_name": "Custom Agreement",
"paperwork_type": "CustomPaperwork",
"worker_type": "Employee",
"jurisdictions_filter": {
"type": "include",
"jurisdictions": ["CA", "NY"]
},
"jurisdiction_type": "Worklocation",
"effective_date": "2023-01-01",
"archive_date": "2023-12-31",
"form_fields": [
{
"field_name": "employee_name",
"label": "Employee Name",
"error_text": "This field is required.",
"type": "string",
"zeal_autofill": true,
"required": true,
"options": null,
"constraint": null,
"description": "Enter the employee's name.",
"x": 10,
"y": 20,
"width": 200,
"height": 50
}
]
}
```
#### Fetching Paperwork Templates
Paperwork templates can be fetched using the [Get Paperwork Templates](/reference/paperwork-api/get-paperwork-templates) endpoint or the [Get Paperwork Template](/reference/paperwork-api/get-paperwork-template-by-id) (GET `/paperwork/templates/{templateID}`) endpoint to fetch a specific template by passing the `templateID`.
## Submitting Paperwork
### Company Dashboard
Workers that fall under a custom paperwork's rulesets will be prompted to complete and submit the paperwork in a new step in onboarding:
### API
Paperwork can also be submitted through the API. To submit a completed paperwork form, use the [Create Paperwork Submission](/reference/paperwork-api/create-paperwork-submission) (PUT `/paperwork/submissions`) endpoint. The endpoint accepts the following body parameters:
* `templateID`: Unique identifier for the paperwork template
* `worker_type`: Type of worker (Employee or Contractor)
* `companyID`: Unique identifier for the company
* `employeeID`: Unique identifier for the employee (nullable if the worker type is contractor)
* `contractorID`: Unique identifier for the contractor (nullable if the worker type is employee)
* `fields`: Additional fields for the paperwork submission. These fields are based on the `form_fields` array on the parent Paperwork Template.
Below is a JSON body example of a PUT `/paperwork/submissions` request:
```bash bash theme={null}
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
}
}
```
## Seeing Paperwork Submissions
### Company Dashboard
All submitted custom paperwork can be viewed along with other onboarding paperwork (such as Form W-4s) under the worker's profile page:
### API
To fetch completed paperwork submissions through the API, use the [Get Paperwork Submissions](/reference/paperwork-api/get-paperwork-submissions) (POST `/paperwork/submissions`) endpoint. The endpoint allows filtering by `companyID`, `jurisdiction_filter`, and `worker_filter`.
Below is a JSON response of a successful POST `/paperwork/submissions` request:
```bash bash theme={null}
{
"success": true,
"data": [
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"submissionID": "a1b2c3d4-e5f6-4a5b-8c7d-9e0f1a2b3c4d",
"submission_date": "2023-06-01T12:00:00Z",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
},
"paperwork_type": "CustomPaperwork",
"url": "https://example.com/submission/12345"
}
]
}
```
## Recap
* Custom Paperwork Templates can only be created in the Zeal UI.
* Custom Paperwork Templates can be viewed using the Zeal UI or Zeal's Paperwork API.
* Paperwork submissions can be completed by the worker in Zeal's onboarding flow, or can be submitted through the API.
* Completed paperwork forms can be viewed in the worker's profile page or fetched using the Submissions API endpoints, associating them with the specific worker and template.
# Customer Accounts (Early Access)
Source: https://docs.zeal.com/docs/customer-accounts-closed-beta
The concept of a Customer Account represents the end-client of a staffing company. Typically staffing companies act like marketplaces, supplying labor to brands who provide work opportunities. Zeal's customer accounts functionality enables staffing companies to map labor and payroll fees to their end-customers. Debits and credits are processed completely on Zeal's payment rails.
**Note:** Customer Accounts is an early access feature. Please contact your Zeal team for more information on this feature
## In this guide
* Which endpoints are needed to integrate with and onboard Customer Accounts.
* A step by step explanation of the onboarding steps.
* Mapping customer accounts to worker checks.
***
## API
Customer accounts are currently only available for integration via **API**.
### Create a Customer Account
The first step of the customer account onboarding process is the creation of customer accounts. Customer account creation is facilitated via the [Create Customer Account ](/reference/customer-accounts/create-customer-account)or POST `/customer-accounts` endpoint. The endpoint requires the following body parameters:
* `code`: A unique custom-set code to associate with the customer account
* `companyID`: The ID of the Zeal company
* `business_name`: The business name of the customer account/end-client
Below is an example of a POST `/customer-accounts` cURL request:
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/customer-accounts \
--header 'Authorization: ' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"code": "23",
"companyID": "2139e98385ce9rer8583erer3048",
"business_name": "Hooli"
}
'
```
The endpoints response will return a newly created `customer_account_id`, the unique Zeal identifier for the customer account. The response will also contain a `status` flag indicating the current status of the customer account, upon first creation - this status will be marked as `initial_onboarding`. Below is an example response from the customer account creation request:
```bash bash theme={null}
{
"data": {
"business_name": "Hooli",
"code": "23",
"company_id": "2139e98385ce9rer8583erer3048",
"customer_account_id": "c7235er9eeedbfb6f1bf962da1a503",
"partner_id": "c93488er943949fcejrer34350359",
"status": "initial_onboarding"
},
"success": true,
"testMode": false
}
```
### Create a Funding Source
The next step of of customer account onboarding is the creation and attachment of a funding source to the newly created customer account. This is accomplished by utilizing the [Create Funding Source](https://dash.readme.com/project/zeal-docs/v1.0/refs/create-funding-source) or POST `/customer-accounts/:{id}/funding-sources`. Similar to creating a bank account for an employee or company within Zeal, the endpoint requires the body parameters of:
* `account_number`: The account number of the bank account
* `routing_number`: The routing number of the bank account
* `account_type`: Type of the bank account (checkings, savings)
* `companyID`: The ID of the Zeal company
* `customerAccountID`: the ID of the customer account
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/customer-accounts/:id/funding-sources \
--header 'Authorization: Bearer ' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"account_type": "checking",
"customerAccountID": "c7235er9eeedbfb6f1bf962da1a503",
"account_number": "12345",
"routing_number": "12345",
"companyID": "2139e98385ce9rer8583erer3048"
}
'
```
### Trigger and Verify Microdeposits
In order to verify the bank account and funding source of the customer account, Zeal utilizes microdeposit verification. Microdeposits are triggered and these values appear on the bank account within 1-3 days as originating from the Zeal company. These values are then passed for verification in order to verify the funding source/account.
To **trigger** microdeposits for a funding source, pass the [Trigger Microdeposits](https://dash.readme.com/project/zeal-docs/v1.0/refs/trigger-ca-microdeposits) or POST `/customer-accounts/:{customerAccountID}/trigger-micro-deposits` endpoint.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/customer-accounts/:c7235er9eeedbfb6f1bf962da1a503/trigger-micro-deposits \
--header 'Authorization: Bearer ' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "2139e98385ce9rer8583erer3048"
}
'
```
To **verify** microdeposits after the values appear in the funding source account, pass the [Verify Microdeposits](/reference/customer-accounts/verify-microdeposits) or POST `/customer-accounts/:{customerAccountID}/verify-micro-deposits` endpoint.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/customer-accounts/:c7235er9eeedbfb6f1bf962da1a503/verify-micro-deposits \
--header 'Authorization: Bearer ' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "2139e98385ce9rer8583erer3048",
"deposits": [
"2",
"1.3"
]
}
'
```
The Customer Account is now fully onboarded and ready to be mapped to worker payments.
## White-Label
### Create a Customer Account
Currently, creating a customer account is only supported in the API. Refer to the [API guide](/docs/customer-accounts-closed-beta#create-a-customer-account) to create a Customer Account.
### Onboarding Flow
Call [Generate Customer Account Onboarding Link](/reference/customer-accounts/generate-customer-account-onboarding-link). This returns a link to the white-label component. You can select if you want the customer account to go through the full onboarding flow - profile information and funding source, or one of the steps.
```bash bash theme={null}
curl --request POST \
--url 'https://api.zeal.com/customer-accounts/onboard' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"customerAccountID": "{{customerAccountID}}",
"profileInfo": true,
"bankInfo": true
}
'
```
Give the employer access to the link.
When the customer account accesses the link, they see the white-label component on your domain with your logo. First, the customer account completes the **Profile Information** section.
Next, the customer account completes the **Bank Linking**. This step has two options -
1. Instant bank verification (Early Access) - Zeal uses **Teller** to securely connect to the customer account's bank account. We collect basic information, including account number and routing number.
2. Microdeposits - This option requires a micro-deposit flow where two small deposits are made to the customer account's bank account. The customer account will leave the onboarding flow and return later to confirm the deposit amount. The micro-deposit flow generally takes 1 - 3 days.
Once a verified bank account has been linked to the customer account, they should be able to start making payments.
## Mapping Customer Accounts to Payments
Customer Accounts can be attached to checks in order to accurately map labor and payroll fees as well as to map disbursed funds from the end-client accounts to the respective workers. To do so, a `customerAccountID` can simply be passed in the [Shift Object](/reference/employee-checks/shifts/shift-object) of the check that you are mapping to a customer account.
```bash bash theme={null}
{
"shiftID": "4712c99283304b7b989179aae36b4590",
"status": "pending",
"employeeID": "1234567890",
"customerAccountID": "c7235er9eeedbfb6f1bf962da1a503", //the Customer Account ID
"employeeCheckID": "1098876345",
"first_name": "erlich",
"last_name": "bachman",
"metadata": {},
"time": "2023-04-15T14:00:00Z",
"wcc_code": "12324",
"hourly": {
"hours": 8,
"wage": 20,
"custom_name": "custom hourly"
},
"overtime": {
"hours": 2,
"wage": 30
},
"reimbursement": {
"amount": 8.5
}
}
```
## Recap
* A customer account is created and onboarded via the API
* Funding sources are attached to customer accounts and require microdeposit verification
* Customer accounts can be mapped to payments by passing the customerAccountID in the respective check's shift object
# Deductions
Source: https://docs.zeal.com/docs/deductions-guide
Along with standard payroll withholdings such as income tax and social security, some employees may need additional deductions withheld from their checks, such as 401K contributions or garnishments.
## In this guide
* What makes up a Deduction Template Definitions.
* How to define deduction rules with a Deduction Template.
* How to add a Deduction to an Employee Check.
* How to create recurring deductions from the Company Dashboard.
***
## API
Accounting for deductions with Zeal's API is a 2-step process:
1. Create a Deduction Template
2. Create a Deduction (scoped to a single Employee Check)
### Understanding Deduction Template Definitions
Before we create a Deduction Template we should first get the Deduction Template Definition Object for the type of deduction (401K, HSA, etc.) we want to address. This object is presented as a [JSON schema](https://json-schema.org/) and defines the instructions, or possible options available, when creating a Deduction Template. This JSON schema can be a little complicated so let's break it down into pieces.
```bash bash theme={null}
// Full HSA Deduction Template Definition Object
{
"type": "object",
"required": [
"employee_contribution",
"additional_fields"
],
"properties": {
"required_template_fields": {
"const": [
"employee_contribution"
]
},
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "hsa"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"additional_fields": {
"type": "object",
"properties": {
"hsa_type": {
"enum": [
"family",
"individual"
]
}
},
"required": [
"hsa_type"
]
}
}
}
```
#### Properties
The first thing to note is the `properties` field.
```bash bash theme={null}
// Snippet Showing Properties
// inner details of objects have been omitted for brevity
{
"properties": {
"required_template_fields": {
},
"custom_name": {
},
"deduction_type": {
},
"employee_contribution": {
"properties": {
"contribution_type": {
},
"value": {
},
"override_type": {
},
"required_template_fields": {
}
},
"employer_contribution": {
"properties": {
"contribution_type": {
},
"value": {
},
"override_type": {
},
"required_template_fields": {
}
},
},
"additional_fields": {
"properties": {
"hsa_type": {
}
},
}
}
}
```
With the exception of `required_template_fields` (more on this later), all keys of a `properties` field directly translate to fields that may be included in the body of your POST request to the [Create a Deduction Template endpoint](/reference/employee-checks/deductions/create-deduction-template).
```bash bash theme={null}
// Example Request Body to Create a HSA Template
{
"companyID": "{{companyID}}",
"deduction_type": "hsa",
"custom_name": "Test HSA",
"employee_contribution": {
"contribution_type": "dollars",
"override_type": "needs_input"
},
"employer_contribution": {
"contribution_type": "dollars",
"value": 0,
"override_type": "overridable"
},
"additional_fields": {
"hsa_type": "individual"
}
}
```
#### Property Values
The Deduction Template Definition also tells us the values we can assign to the fields of each property. There are a few different types of values these fields might hold so let's go through them.
* `const` - field is restricted the value listed.
* `enum` - field is restricted to one of the values listed.
* `type` - field is restricted to the *type* listed (ex. `"number"`-> `5`).
```bash bash theme={null}
// Snippet Showing Property Values
{
"properties": {
"deduction_type": {
"const": "hsa"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
}
}
}
}
}
```
### Note
While most values are self-explanatory, the values of the `override_type` property may be unfamiliar. Please see our [API Reference](/reference/employee-checks/deductions/get-deduction-template-definitions#override-types) for details on these values.
#### Required Fields
In example request body above, we included all of the property options that were listed in the HSA template definition. However, not all of the properties are required. The `required` fields tell us what properties must be included in our request.
```bash bash theme={null}
// Snippet Showing Required Field
{
"required": [
"employee_contribution",
"additional_fields"
],
}
```
With this in mind, another valid request body to create an HSA template could be as follows since `employer_contribution` is not a required field.
```bash bash theme={null}
// Example Request Body to Create a HSA Template
{
"companyID": "{{companyID}}",
"deduction_type": "hsa",
"custom_name": "Test HSA",
"employee_contribution": {
"contribution_type": "dollars",
"override_type": "needs_input"
},
"additional_fields": {
"hsa_type": "individual"
}
}
```
### Note
The fields `companyID`, `deduction_type`, and `custom_name` are always required.
#### Conditionally Required Fields
One part of the schema that may not be immediately understood is the `allOf` fields.
```bash bash theme={null}
// Snippet Showing allOf field
{
"properties": {
"employee_contribution": {
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
]
}
}
}
```
These fields contains an array of *condition objects* that define when properties may be required depending on the value of another field.
```bash bash theme={null}
// Snippet Showing a Conditional Object within allOf array
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
```
For example the snippet above should be understood as "*if the`override_type` is set to `final`, then the property `value` will also be required*.
With this in mind, it would be valid to create a HSA Deduction Template as follows:
```bash bash theme={null}
// Example Request Body to Create a HSA Template
{
"companyID": "{{companyID}}",
"deduction_type": "hsa",
"custom_name": "Test HSA",
"employee_contribution": {
"contribution_type": "dollars",
"override_type": "needs_input"
},
"additional_fields": {
"hsa_type": "individual"
}
}
```
However, the following example would be invalid:
```bash bash theme={null}
// Example Of Invalid HSA Request Body
{
"companyID": "{{companyID}}",
"deduction_type": "hsa",
"custom_name": "Test HSA",
"employee_contribution": {
"contribution_type": "dollars",
"override_type": "final" // if "final" then "value" is required
// missing "value" field here
},
"additional_fields": {
"hsa_type": "individual"
}
}
```
Attempting the request above will produce this error:
```bash bash theme={null}
// Example Of Error Produced by Invalid Request
{
"success": false,
"errors": [
{
"message": "Invalid deduction template. Ensure deduction template matches template definition",
"code": 13
}
]
}
```
#### Required Template Fields
With everything we've learned so far, we're ready to create Deduction Templates. But you may be thinking, "*Hold on. What about this`required_template_fields`?*". Great question!
`required_template_fields` aren't actually included when creating a Deduction Template. Rather these fields tell us what fields will be required in the subsequent step to create a Deduction using the template.
For example, our HSA Template Definitions state these `required_template_fields`:
```bash bash theme={null}
// Snippet Showing Required Template Fields
{
"properties": {
"required_template_fields": {
"const": [
"employee_contribution"
]
},
"employee_contribution": {
"required_template_fields": {
"const": [
"value"
]
}
},
}
}
```
This means that when we create a Deduction using this Deduction Template, we'll need to include the `employee_contribution` object with the field `value` in our `deduction` object.
```bash bash theme={null}
// Example Request Body to Create a HSA Deduction
{
"companyID": "{{companyID}}",
"deductionTemplateID": "{{deductionTemplateID}}",
"employeeCheckID": "{{employeeCheckID}}",
"deduction": {
"employee_contribution": {
"value": 50
}
}
}
```
With this, we have a full, thorough understanding of Deduction Template Definitions. Thankfully, this is the most difficult step in the process of creating deductions. Now, we can easily complete the 2-step flow.
### Create a Deduction Template
A Deduction Template is an object that defines the schema for a Deduction. Deduction Templates may be reused across a company for many employees or may just be reused to create deductions for a single employee.
For example:
* An employer might create a 401K Deduction Template that defines a fixed *employer contribution* but allows the *employee contribution* to be adjusted with each deduction created. This might be reused across multiple employees.
* An employee has a particular case where many garnishments or miscellaneous need to be withheld from their paycheck. The Deduction Templates that are defined to accommodate this use case might only be used to create deductions for this particular employee.
It's important to understand the scope of a Deduction Template before creating it. Now we'll walk through creating a Deduction Template.
1. Call [Get Deduction Template Definitions](/reference/employee-checks/deductions/get-deduction-template-definitions) with the type of deduction you're targeting as a query parameter. We'll choose `401k` for this example.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the examples below.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/deductionTemplateDefinitions?deduction_type=401k' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
2. Use the JSON Schema returned as instructions to build your request to create a deduction template.
3. Call [Create Deduction Template](/reference/employee-checks/deductions/create-deduction-template).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/deductionTemplate \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"employee_contribution": {
"override_type": "needs_input",
"contribution_type": "percentage",
"value": 3
},
"employer_contribution": {
"override_type": "final",
"contribution_type": "dollars",
"value": 200
},
"companyID": "{{companyID}}",
"custom_name": "My 401k Template",
"deduction_type": "401k"
}
'
```
4. Store the returned `deductionTemplateID` for use when creating deductions following this template.
***
### Create a Deduction
A Deduction defines how much should be withheld from an employees pay and is scoped to a single Employee Check. Below are the steps to create a Deduction.
1. [Get Employee Checks by Employee](/reference/employee-checks/employee-checks/get-employee-checks-by-employee) you'd like to apply the Deduction to.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/employeeCheck?companyID={{companyID}}&employeeID={{employeeID}}&status=pending&reportingPeriodID={{reportingPeriodID}}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
2. [Get a list of Deduction Templates](/reference/employee-checks/deductions/get-deduction-template) and grab the `deductionTemplateID` for the desired template (or use the ID you stored from the previous steps).
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/deductionTemplate?companyID={{companyID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
3. [Create the Deduction](/reference/employee-checks/deductions/create-deduction).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/deductions \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"deductionTemplateID": "{{deductionTemplateID}}",
"employeeCheckID": "{{employeeCheckID}}",
"deduction": {
"employee_contribution": {
"value": 50
}
}
}
'
```
With your deduction in the system Zeal will pick up the Deduction when the Employee Check is processed. Zeal will properly calculate the taxes depending on the type of Deduction (post-tax or pre-tax), the employee will receive their net pay, and the deduction amount will remain in the company's bank account (**Note:** `garnishments` are the exception. These amounts will be deducted from the company's bank account and paid out to the proper stakeholders by Zeal).
***
## White-Label
From the white-label Company Dashboard, users can create recurring deductions which will automatically be added to future payroll runs. Please reference our [Payroll Runs](/docs/payroll-runs) guide to understand payroll runs.
### Accessing the deductions page
Navigate to **Run Payroll** and click **Get started** under **Manage deductions**.
On the following page, click on the deduction type we want to manage. There are many types, but we'll stick to the common 401K for this guide.
### Creating a 401K deduction
Under the 401K page, check the box next to the employee's you'd like to add the deduction for, fill the **Custom Name**, **Employee Contribution**, and **Employer Contribution** sections, then click **Add new deduction**.
Back on the Manage Deductions page, we can see that we now have 2 401K deductions.
Now these deductions will automatically be added to any future payroll runs.
***
## Recap
* Understanding the Deduction Template Definitions is key to managing deductions with Zeal.
* A Deduction Template defines the rules for your deductions.
* Deductions are created using a Deduction Template and applied to an Employee Check.
* With a deduction attached to an Employee Check, the deduction will automatically be applied when the check is processed.
* From the white-label Company Dashboard, you can create recurring deductions.
* Recurring deductions will be automatically added to future *regular* payroll runs.
# Deduction Types
Source: https://docs.zeal.com/docs/deductions-types
Below are brief descriptions of Zeal-supported deductions and how they are taxed.
| Deduction Type | Description | Effect on Taxes |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| Section 125 | Section 125 deductions refer to pre-tax contributions made by employees under a Section 125 plan, also known as a Cafeteria Plan. This section is part of the U.S. Internal Revenue Code (IRC) and allows employees to choose between receiving taxable cash or tax-free benefits. Costs for accident or disability income insurance, liability insurance including general and automobile liability insurance, supplement to liability insurance, hospital indemnity, other fixed indemnity or coverage only for a specificized disease or illness that are includable in the employees' gross income. Section 125 contributions will be mapped to Box 14 on the W-2. | Pre-Tax |
| Health Savings Account (HSA) | A health savings account (HSA) is a tax-advantaged medical savings account enrolled in a high-deductible health plan. Funds accumulate and can be used to pay for qualified medical expenses without tax liabilities. HSA contributions will be mapped to Box 12W on the W-2. | Pre-Tax |
| Traditional 401(k) | A 401(k) plan is a tax-qualified, defined-contribution pension account that provides for pre-tax retirement savings. 401(k) contributions are mapped to Box 12D on the W-2. | Pre-Tax |
| Roth 401K | A Roth 401(k) plan is similar to the 401(k) plan, but where employees contribute post-tax funds and can withdraw tax free given certain criteria. Roth 401(k) contributions are mapped to Box 12AA on the W-2. | Post-Tax |
| Roth IRA | A Roth IRA is an Individual Retirement Account to which you contribute after-tax dollars. While there are no current-year tax benefits, your contributions and earnings can grow tax-free, and you can withdraw them tax-free and penalty free after age 59½ and once the account has been open for five years. Roth IRA contributions are mapped to Box 14 on the W-2. | Post-Tax |
| Simple IRA | A Savings Incentive Match Plan for Employees Individual Retirement Account (SIMPLE IRA) is a tax-deferred employer-provided retirement plan that allows employees to set aside money and invest it to grow for retirement. Simple IRA contributions are mapped to Box 12S on the W-2. | Pre-Tax |
| 403(b) | A 403(b) plan is a retirement savings plan available to qualified non-profit groups. It has a tax treatment similar to a 401(k). 403(b) contributions are mapped to Box 12E on the W-2. | Pre-Tax |
| Employer Sponsored Health Coverage | A benefit belonging to a Section 125 Cafeteria plan that helps employees pay for qualified expenses related to medical, dental, and vision care. Employer Sponsored Health Coverage contributions are mapped to box 12DD on the W-2. | Pre-Tax |
| Dependent Care Benefit | Dependent care benefits are a series of benefits that employers may choose to offer employees to help them with the costs of caring for family members or those who rely on them for care. These benefits can be used to reduce the cost of daycare, after-school care, elder care, and more - as long as the costs are work-related. Dependent Care Benefits are often a form of an Flexible Spending Account (FSA). Dependent Care Benefit contributions are mapped to Box 10 on the W-2. | Pre-Tax |
| Garnishment | A garnishment is a court-mandated withholding of an employee's earnings from a paycheck for use toward debts. Common sources include child support, federal debt, state debt, student loans, and credit card debt. This serves as a post-tax deduction. Garnishments are not reported on the W-2. | Post-Tax |
| Miscellaneous | A type for a generic post-tax deduction on the employee check. Miscellaneous deductions are not reported on the W-2. | Post-Tax |
You can see how to use Deductions in payroll in the [Deductions Guide](/docs/deductions-guide).
# Earning Components
Source: https://docs.zeal.com/docs/earning-components
Earning Components define categories of compensation and determine how each is taxed according to tax laws and regulations.
Below are descriptions of Zeal's earning components and how they are taxed:
| Earning Type | Description | Wage Type |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| Advance | An advance is a form of loan or payment where money or goods are provided before any return consideration is received. Advanced earnings are taxed the same as regular earnings. Advances are not exempt from any specific tax types. | Regular |
| Cash Tips | Tips that an employee has received in cash prior to their paycheck date. Cash tips will be taxed normally, but will not be included in the employee net pay because they have already received them. Cash tips are not exempt from any specific tax types. | Regular |
| Charged Tips | Tips that an employee has not yet received. Paycheck tips will be taxed normally and will also be included in the employee net pay. Example being credit card tips. Charged tips are not exempt from any specific tax types. | Regular |
| Commission | Payment to an employee based on commission. Commission earnings are taxed differently than regular earnings. They are taxed at a jurisdiction's supplemental rate when applicable. Commission earnings are not exempt from any specific tax types. | Supplemental |
| Commodity | Commodity wages, also known as "in kind wages", are a way for agricultural producers to compensate employees by transferring ownership of a commodity (such as hay, cattle, etc) to them instead of paying cash. Commodity wages are not subject to FICA taxes, Federal or State unemployment taxes, and no federal/state income tax is withheld (although the wages are subject to these tax types). | Commodity |
| Correction | Correction wages are a negative gross pay amount meant to represent a correction to a shift where an employee was previously overpaid. The employer enters the correction as a positive number and it will convert the number entered into a negative gross pay amount. | Other |
| Discretionary Bonus | Bonus payment to an employee given at the sole discretion of the employer. The key is that the employer hasn't set the expectation of a bonus if employees meet certain goals. Bonus earnings are taxed differently than regular earnings. Discretionary bonuses are not exempt from any specific tax types. | Supplemental |
| Double Time | Any hours worked by the employee that constitute double overtime. Overtime earnings are taxed the same way as regular earnings. Double time is not exempt from any specific tax types. | Regular |
| Flat | A way to pay an employee a set gross amount, without consideration for hourly rate or hours worked. Flat earnings are taxed the same way as regular earnings. Flat earnings are not exempt from any specific tax types. | Regular |
| Gross Up | Gross up allows an employer to enter what they want an employee to be paid out in net wages and automatically calculates the gross pay needed to achieve the desired net pay. Gross up wages are taxed the same way as regular earnings. Gross up earnings are not exempt from any specific tax types. | Regular |
| Group Term Life Insurance Cost Over 50000 | For most employees, the imputed cost of coverage in excess of \$50,000 for Group Term Life (GTL) must be included in income. The total can be calculated using the IRS Premium Table. GTL imputed income amounts are subject to social security and Medicare taxes. | Other |
| Holiday | Any hours worked by the employee on a holiday. Paid holiday earnings are taxed the same way as regular earnings. Holiday earnings are not exempt from any specific tax types. | Regular |
| Hourly | Regular hours worked by hourly employees. Hourly earnings are not exempt from any specific tax types. | Regular |
| Meal Break Premium | A 30 minute meal break is required for an employee for every five hours worked in a workday. If the employer fails to provide a meal break or the meal break is waived then the employer must pay the employee one additional hour of pay at the employee's regular rate of pay for each workday that the meal period is not provided. | Regular |
| Nondiscretionary Bonus | Bonus payment to an employee offered by an employer if employees meet certain requirements. These are usually standing offers that help incentivize better performance in the workplace. Nondiscretionary Bonus earnings are taxed the same way as regular earnings. Nondiscretionary Bonuses are not exempt from any specific tax types. | Regular |
| Overtime | Any hours worked by the employee that constitute overtime. Overtime earnings are taxed the same way as regular earnings. Overtime earnings are not exempt from any specific tax types. | Regular |
| PTO | Paid time off (PTO) describes time for which an employee is paid, but during which they did not work. PTO earnings are taxed the same way as regular earnings. PTO earnings are not exempt from any specific tax types. | Regular |
| Piecework | Work where the employees are paid at a fixed piece rate for each unit produced. Piece earnings are taxed the same way as regular earnings. Piecework earnings are not exempt from any specific tax types. | Regular |
| Reimbursement | Money given to an employee to reimburse the employee for self paid job related expenses. A reimbursement is not taxable. | Non-Taxable |
| Rest Break Premium | A 10 minute rest break is required for an employee for every four hours worked in a workday. If the employer fails to provide a rest break or the rest break is waived then the employer must pay the employee one additional hour of pay at the employee's regular rate of pay for each workday that the rest period is not provided. | Regular |
| Sick | Paid time during which the employee was not working due to sickness. Sick earnings are taxed the same way as regular earnings. Sick pay is not exempt from any specific tax types. | Regular |
| Vacation | Vacation pay is compensation that employees receive while they take time off from work for vacation. Vacation earnings are taxed the same way as regular earnings. Vacation pay is not exempt from any specific tax types. | Regular |
| 2% S-Corp Health Insurance | Health and accident insurance premiums paid on behalf of a greater than 2-percent S corporation shareholder-employee are deductible by the S corporation and reportable as wages on the shareholder-employee's Form W-2, subject to income tax withholding. | Other |
| Owner's Draw (Early Access) | Money withdrawn by a business owner from company profits for personal use. This is not considered wages or salary, and no payroll taxes are withheld. | Non-Taxable |
You can see how to include earning components in the [Shifts API](/reference/employee-checks/shifts/shift-object) here.
# Employee Checks
Source: https://docs.zeal.com/docs/employee-checks-guide
With Zeal, paying employees is a simple matter of creating Employee Checks with the desired check_date (or payday).
## In this guide
* What makes up an Employee Check.
* How to get Reporting Periods.
* How to create an Employee Check.
* How Employee Checks are represented in the Company Dashboard and how to edit them.
***
## Components of an Employee Check
### Reporting Period
[Reporting Periods](/reference/employee-checks/reporting-periods/reporting-period-object) refer to the period of time for which the employee is being compensated. Reporting periods correlate with the pay schedule for the employee. For example, if the employee is on a semi-monthly pay schedule, a normal reporting period may span Jan. 1st - Jan. 15th. If the employee is on a daily pay schedule, the reporting period could be any day of the year. See [Pay Frequency, Reporting Periods and Check Dates](/reference/employee-checks/reporting-periods/pay-frequency-reporting-periods-and-check-dates) for more details.
### Check Date
The Check Date states what day the employee should be paid. This date is essential to how Zeal runs payroll. At 2 PM Pacific Time two days prior to any given Check Date (12:30 PM P.T. for `one-day` speed checks), Zeal will batch all Employee Checks with the same `check_date` together into one Employer Check (essentially a payroll run). Zeal will debit the company's bank account the gross total and use it to pay out the net earnings to all employees by the Check Date.
### Shifts
[Shifts](/reference/employee-checks/shifts/shift-object) define the compensation the employee has earned. Shifts will include one or many earning components such as hourly wages, overtime wages, PTO, commission, etc. (read more about Zeal's Earning Components [here](/docs/earning-components)) You can manage Shifts by creating the Employee Check upfront and then adding shifts to the existing check or by including all Shifts directly in the initial request to create the Employee Check.
### Deductions (Optional)
[Deductions](/reference/employee-checks/deductions/get-deduction-template-definitions) refer to specific withholdings from an employee's pay. Common deductions include 401K, HSA, and garnishments. Deductions are important for the calculation of taxes and the reporting on paystubs. Zeal will use the deduction in our gross-to-net calculation but will not debit the deduction from the company's bank account (with the exception of garnishments). The company is responsible for paying out the proper stakeholders for the deduction.
## API
### Get the Reporting Period
Call [Get Reporting Period by Date Range](/reference/employee-checks/reporting-periods/get-reporting-period-by-date-range) to get the proper reporting period for this check.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/reportingPeriod?companyID={{companyID}}&pay_schedule=semimonthly&searchStart=2022-01-01&searchEnd=2022-01-15' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
### Create an Employee Check
Call [Create Employee Check](/reference/employee-checks/employee-checks/create-employee-check).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employeeCheck \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"approval_required": false,
"disbursement": {
"method": "direct_deposit"
},
"shifts": [
{
"flat": {
"hours": 80,
"amount": 2500
},
"time": "2023-02-24T15:00"
}
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2022-01-14"
}
'
```
With the check in our system, it will automatically be batched and begin processing 2 days before the `check_date`.
***
## White-Label
Employee Check are represented slightly differently in the white-label than in the API. Employee Checks are grouped as payroll runs in the white-label. Thus, creating or editing and Employee Check will always be done as part of a payroll run. To create a payroll run, please see our [Payroll Runs](/docs/payroll-runs) guide. Below we'll cover how to edit an already existing Employee Check through the white-label.
### Access through the Company Dashboard
Navigate to your Partner Dashboard and ensure that *Test Mode* is enabled. Then, click on a Company to access the Company Dashboard as an Admin.
### Find an Employee Check
Navigate to **Pay > Pending** and click on the check you want to edit.
### Edit the check
On the following page, click **Edit employee check**.
This will bring us to the **Run payroll** tab where we'll see our check represented as a payroll run. By clicking the pencil icon, we can edit any part of the check, including other earnings and deductions.
In the modal that appears, we can edit the details of the check.
### Save changes to the check
Once the check is edited as we like, we can click **Save changes for later** or **Continue** if we'd like to approve the payroll run for processing.
### Payroll runs
More information about payroll runs can be found in our [Payroll Runs](/docs/payroll-runs) guide.
***
## Recap
* Employee Checks have many components that inform Zeal of how to process the check.
* You can get a reporting period for a check using the [Get Reporting Period by Date Range](/reference/employee-checks/reporting-periods/get-reporting-period-by-date-range) endpoint.
* You can create a check with the [Create Employee Check](/reference/employee-checks/employee-checks/create-employee-check) endpoint.
* Employee Checks are grouped inside Payroll Runs in the Company Dashboard.
* Employee Checks are edited as part of a Payroll Run from the Company Dashboard.
# Employee Dashboard
Source: https://docs.zeal.com/docs/employee-dashboards-guide
An essential piece of your payroll product is the Employee Dashboard. Employees need a space to review paystubs and payment history, manage their profile information, and review tax information.
## In this guide
* Which endpoints are needed to recreate the Employee Dashboard.
* How to embed the white-label Employee Dashboard in your application.
***
## API
We’ll use **Zeal’s white-labeled Employee Dashboard** as a reference for building our custom dashboard.
### How to build a Home Page
1. Call [Get Employee Checks by Employee](/reference/employee-checks/employee-checks/get-employee-checks-by-employee) to present a summary of checks for this employee.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/employeeCheck?companyID={{companyID}}&employeeID={{employeeID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
2. Call [Get Paystub Link](/reference/zeal-components/get-paystub-link) to allow employees to download specific paystubs.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/paystubLink?companyID={{companyID}}&employeeCheckID={{employeeCheckID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
### How to build a Profile Page
1. Call [Get/Update Employee Information](/reference/employees/get-employee-information) to allow the employee to view/edit their profile information.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/employees?companyID={{companyID}}&employeeID={{employeeID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
2. Call [Get Employee Tax Parameter Summary](/reference/employee-onboarding/get-employee-tax-parameter-summary) and [Set Employee Tax Parameters](/reference/employee-onboarding/set-employee-tax-parameters) allow the employee to view/edit their tax information.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees/getTaxParameterSummary \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"jurisdictions": [
"US",
"CA"
],
"employeeID": "{{employeeID}}",
"companyID": "{{companyID}}"
}
'
```
3. Call [View/Sign Employee Paperwork](/reference-link/employee-paperwork) to present tax documents (federal & state W-4s) in a PDF format.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/paperwork/employeePaperwork \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"jurisdiction": "US",
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"signature_text": "iVBORw23goAAAANSUhEUgAAAtsAAABdCAYAAAB0BqpEAAABRmlDQ1BJQ0MgUHJvZmlscccKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8bAwiDLwMfAxSCYmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsispF"
}
'
```
4. Call [Get Bank Account by Employee/Contractor ID](/reference/bank-accounts/get-bank-accounts-by-worker-id) to present bank account information. Use [Update Bank Account](/reference/bank-accounts/update-bank-account) to allow the employee to correct their bank information.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/bankaccount?companyID={{companyID}}&id={{employeeID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
### How to build an Employee Documents section
Call [Get Documents](/reference/documents/get-documents) to retrieve a list of employee documents such as W-2s or W-2 Cs.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/documents?companyID={{companyID}}&id={{employeeID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
***
## Zeal's White-Labeled Dashboard
There are two ways to allow an Employee to access their dashboard.
### SSO Link
1. If you’ve already authenticated the employee on your system, call [Generate Employee Dashboard Link](/reference/zeal-components/generate-employee-contractor-dashboard-link) to get an SSO link directly to the employee's dashboard.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/getAuthLink'
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json'
--data-raw '
{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}"
}
'
```
2. Now, allow the employee to access the link or embed the component directly in your application through an iframe .
```bash bash theme={null}
Click to begin payroll onboarding!
```
### Login Credentials
During the [Employee Onboarding](/docs/employee-onboarding-guide), include the account creation step by setting `"employee_acct": true`.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees/onboard \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"profile": true,
"employee_acct": true,
"i9_form": false,
"id_scan": false,
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}"
}
'
```
2. The employee creates credentials that they can use to log into their Employee Dashboard.
3. The employee navigates to your domain (e.g. payroll.\[your-domain].com) and inputs their credentials to log in.
***
## Recap
* The Employee Dashboard provides core functionality to your payroll products such as allowing employees to access paystubs and personal information.
* All the data and processes needed to build your customer employee dashboard are exposed through Zeal's API endpoints.
* You may embed the white-label Employee Dashboard directly in your application.
# Employee Onboarding
Source: https://docs.zeal.com/docs/employee-onboarding-guide
Onboarding W-2 Employees is an important step for any payroll offering.
### Note
Before you onboard an employee, you should define where they will be working. Follow the [Work Locations Guide](/docs/work-locations-guide) to do so.
Onboarding W-2 Employees is an important step for any payroll offering. There are a lot of factors that determine an employee’s taxable status which is necessary to pay them correctly. As such, there are a few steps involved with onboarding an employee.
## In this guide
* How to get an employee's Work Location
* How to create an Employee
* How to complete Tax paperwork
* How to add an employee's Bank Account
* How to update an employee's onboarded status
* How to onboard an employee using the white-label components
***
## API
### Get the employee's Work Location
Call [Get Work Locations](/reference/work-locations/get-work-locations) and find the Work Location for this employee. Store the `workLocationID`.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request GET \
--url https://api.zeal.com/workLocations \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
### Create an Employee
Call [Create Employee](/reference/employees/create-employee) with the employee data along with the `companyID` and `workLocationID`.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data-raw '
{
"new_employees": [
{
"overtime_rate": 1.5,
"double_time_rate": 2,
"autopilot": {
"autopilot_on": false
},
"is_943": false,
"is_scheduleH": false,
"email": "[email protected]",
"first_name": "Richard",
"last_name": "Hendricks",
"title": "CEO",
"default_pay_schedule": "semimonthly",
"default_wage": 50,
"workLocationID": "{{workLocationID}}",
"start_date": "2022-01-01",
"dob": "1985-05-25",
"ssn": "123456789",
"phone_number": "1234567890",
"address": "1 Market St.",
"city": "San Francisco",
"state": "CA",
"zip": "94110"
}
],
"companyID": "{{companyID}}"
}
'
```
Store the `employeeID` or IDs from the employee objects returned.
### W4s: Fetching Paperwork Templates
Tax Paperwork information (most commonly W4 information) can be sent to Zeal using the Paperwork endpoints.
**Note**: if you don't submit W4 information for an employee, Zeal will use the default tax parameters based on work and residency location of the worker.
The [Paperwork Template object](/reference/paperwork-api/paperwork-template-object) outlines the fields that represent a Paperwork Template, which includes key information such as the name of the form, the applicable jurisdiction(s), and the fields on the form. For the purposes of this guide, we will be focusing on Paperwork Templates with `paperwork_type` as `W4`.
Paperwork Templates can be fetched using the [Get Paperwork Template](/reference/paperwork-api/get-paperwork-templates). Be sure to include the jurisdiction(s) and the effective date for the W4 form(s) you want to retrieve.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/paperwork/templates \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "fc235fcccee46aa8a082f357715bcfa",
"paperwork_type": "W4",
"worker_type": "Employee",
"jurisdictions": {
"type": "include",
"jurisdictions": [
"CA"
]
},
"jurisdiction_type": "WorkLocation",
"effective_date": "2023-07-01"
}
'
```
This will return the templateID for the California W4 that you will need when creating a Submission. Here is an example response:
```bash bash theme={null}
{
"templates": [
{
"templateID": "template_123456",
"companyID": "fc235fcccee46aa8a082f357715bcfa",
"form_name": "W-4 Form",
"description": "Employee's Withholding Certificate",
"paperwork_type": "W4",
"worker_type": "Employee",
"jurisdictions_filter": {
"type": "include",
"jurisdictions": [
"CA"
]
},
"jurisdiction_type": "WorkLocation",
"effective_date": "2023-07-01",
"archive_date": null,
"form_fields": [
{
"field_name": "employee_name",
"label": "Employee's Full Name",
"type": "string",
"required": true
}
],
"urls": [
"https://example.com/w4_form.pdf"
],
"status": "Live"
}
]
}
```
Note that the Paperwork Template also includes a URL containing the form in case you want to show a worker what they are filling out.
### W4s: Submitting Paperwork
To submit a completed W4 form, use the [Create Paperwork Submission](/reference/paperwork-api/create-paperwork-submission) or PUT `/paperwork/submissions` endpoint. The endpoint accepts the following body parameters:
* `templateID`: Unique identifier for the Paperwork Template (from previous step)
* `worker_type`: Type of worker (employee)
* `companyID`: Unique identifier for the company
* `employeeID`: Unique identifier for the employee (nullable if the worker type is contractor)
* `contractorID`: Unique identifier for the contractor (nullable if the worker type is employee)
* `fields`: The completed fields and values
Below is a JSON body example of a PUT `/paperwork/submissions` request:
```bash bash theme={null}
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
}
}
```
This will save the completed W4 paperwork submission for this employee.
### W4s: Fetching Paperwork Submissions
You can always fetch the completed paperwork submission(s) using the [Get Paperwork Submissions](/reference/paperwork-api/get-paperwork-submissions) or POST `/paperwork/submissions` endpoint. The endpoint allows filtering by `paperwork_type`, `companyID`, `jurisdiction_filter`, and `worker_filter`.
Below is an example JSON response of a successful POST `/paperwork/submissions` request:
```bash bash theme={null}
{
"success": true,
"data": [
{
"templateID": "123e4567-e89b-12d3-a456-426614174000",
"submissionID": "a1b2c3d4-e5f6-4a5b-8c7d-9e0f1a2b3c4d",
"submission_date": "2023-06-01T12:00:00Z",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"fields": {
"field1": "value1",
"field2": "value2"
},
"paperwork_type": "W4",
"url": "https://example.com/submission/12345"
}
]
}
```
### Add a Bank Account (optional)
### Note
This step is optional. If an employee is onboarded without bank account details they will still be able to receive employee checks by any disbursement method other than `direct_deposit`.
To add a bank account for the employee call [Create Bank Account](/reference/bank-accounts/create-bank-account) to create the employee bank account.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/bankaccount \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"companyID": "{companyID}",
"id": "{{employeeID}}",
"institution_name": "Chase",
"account_number": "123456789",
"routing_number": "267084131",
"type": "checking"
}
'
```
### Update an employee's onboarded status
Call [Set Onboarded Status to True](/reference/employee-onboarding/set-onboarded-status-to-true) to mark the employee status as `onboarded`.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees/setOnboardedStatusToTrue \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"employeeID": "{{employeeID}}",
"companyID": "{{companyID}}"
}
'
```
Now that the employee's status is updated, they are considered onboarded.
***
## White-Label
### Access the Company Dashboard
Navigate to your Partner Dashboard and ensure that **Test Mode** is enabled. Then, click on a Company to access the Company Dashboard as an Admin.
### View a Work Location
Navigate to the **Work Location** page and ensure you have the location that the employee will be working at.
### Create an Employee
Next, navigate to the **People** page and click **Add Employee**.
Fill the employee information and select the proper Work Location from the dropdown, then click **Add Employee**.
### Complete the onboarding flow
Back on the **People** page, find the Employee and click **Copy onboarding link** then **Send link to employee's email**.
### Tip
The link can also be accessed programmatically by calling [Generate Employee Onboarding Link](/reference/employee-onboarding/generate-employee-onboarding-link).
When the employee navigates to the page, they see the white-label component on your domain with your logo.
The employee completes the onboarding flow and they receive a congratulations message showing that they've been onboarded.
### Note
When the Employee Onboarding flow is completed successfully through the white-label, Zeal sends the Employee information to the webhook URL you've set for the [Employee Onboarding Event](/reference/webhooks/employee-onboarding-event).
***
## Recap
* To onboard an employee, personal information, work location, and W4 information need to be submitted.
* Bank account details don't need to be submitted, but the employee can't be paid by direct deposit without them.
* Companies can create Work Locations and employees from the Company Dashboard
* Employees can complete onboarding through the Employee Onboarding component
# Company Onboarding
Source: https://docs.zeal.com/docs/employer-onboarding-guide
A key piece of the payroll solution is company onboarding. Companies must submit basic company information, bank account details, and legal paperwork that Zeal uses to run payroll on their behalf. For Partners building an internal payroll solution, onboarding can be done directly from the Partner Dashboard. However, for Partners that want to sell their payroll product to companies, company onboarding should be integrated within the solution.
## In this guide
* How to create a Company.
* How to verify microdeposits.
* How to gather legal documents.
* How to onboard a company with the white-label Company Onboarding component.
***
## API
The first step to onboarding a company using the API is to create a Company. A Company is what Zeal uses to represent an company's data.
### Create a Company
Call [Create Company](/reference/companies/create-company).
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"partnerID": "{{partnerID}}",
"first_name": "Richard",
"last_name": "Hendricks",
"email": "[email protected]",
"business_name": "Pied Piper",
"business_ein": "12-3456789",
"business_address": "5941 Newell Rd.",
"business_city": "Palo Alto",
"business_state": "CA",
"business_zip": "94303",
"business_phone": "6504441234",
"skip_migration": true
}'
```
### Create a Bank Account
Next we need to submit the bank account that Zeal will use to fund payroll.
Call [Create Company Bank Account](https://docs.zeal.com/reference/create-company-bank-account-beta).
Make sure the `routing_number` is a valid routing number in the United States.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies/bank'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"companyID": "{{companyID}}",
"account_number": "123456789",
"routing_number": "123456789",
}'
```
### Verify microdeposits
For payroll processing, we need to verify the company's bank account through microdeposits.
Call [Trigger Microdeposits](/reference/company-onboarding/trigger-microdeposits) to send the microdeposits to the company's bank account.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies/microdeposits/trigger'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"companyID": "{{companyID}}",
}'
```
The microdeposits should appear in the company's bank account within 2-3 business days. Collect the deposit amounts from the company and call [Verify Microdeposit Values](/reference/company-onboarding/verify-microdeposit-values).
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies/microdeposits/verify'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"companyID": "{{companyID}}",
"deposits": [
"0.14",
"0.09"
]
}'
```
With the bank account added and verified, you can move to the next step.
### Gather documents
For Zeal to legally process payroll for a company, we require authorization documents.
Call [Get Company Authorization Documents](/reference/company-onboarding/get-company-authorization-documents) to get links to the documents which must be signed.
```bash bash theme={null}
curl --location --request GET 'https://api.zeal.com/companies/authorization_documents?companyID={{companyID}}&document_key=all'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
```
Use the links returned to present the documents to the company. Gather their signature for the documents as a base64 string, then call [Sign Company Authorization Documents](/reference/company-onboarding/create-company-authorization-documents).
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies/authorization_documents'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"companyID": "{{companyID}}",
"document_key": "all",
"signature": "iVBORw23goAAAANSUhEUgAAAtsAAABdCAYAAAB0BqpEAAABRmlDQ1BJQ0MgUHJvZmlscccKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8bAwiDLwMfAxSCYmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsispF"
}'
```
With the documents signed and submitted, you can proceed to the final step.
### Update the onboarded status
Lastly, we need to update the onboarded status of the company. Zeal will perform internal checks to ensure that the company can be onboarded.
Call [Set Company Onboarded Status to True](/reference/company-onboarding/set-company-status-to-onboarded).
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies/onboardCompany'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"companyID": "{{companyID}}",
}'
```
***
## White-Label
Onboarding companies through Zeal's white-label Company Onboarding component reduces complexity and cuts down on developer work.
### Pre-fill company profile information (optional)
In some cases, you may prefer to pre-fill the company profile information with details already collected. This helps reduce friction and provides a better experience for the company.
Call [Create Company](/reference/companies/create-company) to submit the company information. This will return a JSON object representing the Company data.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --location --request POST 'https://api.zeal.com/companies'
--header 'Accept: application/json' \
--header 'Content-Type: application/json'
--header 'Authorization: Bearer {{testAPIKey}}'
--data-raw '{
"partnerID": "{{partnerID}}",
"first_name": "Richard",
"last_name": "Hendricks",
"email": "[email protected]",
"business_name": "Pied Piper",
"business_ein": "12-3456789",
"business_address": "5941 Newell Rd.",
"business_city": "Palo Alto",
"business_state": "CA",
"business_zip": "94303",
"business_phone": "6504441234",
"skip_migration": true
}'
```
Get the `companyID` from the returned data and include it in the next step.
### Onboarding Flow
Call [Get Company Onboarding Link](/reference/companies/get-company-onboarding-link). This returns a link to the white-label component.
### Note
If you previously created the company and want Zeal to pre-fill the first section of the onboarding flow, add the `companyID` as a query parameter in the call below.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/companies/onboard?partnerID={{partnerID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
Give the company access to the link. Generally our partners chose to include the link in their application or display the component directly within an iframe.
```bash bash theme={null}
Click to begin payroll onboarding!
```
When the company accesses the link and they see the white-label component on your domain with your logo. First, the company completes the **Profile Information** section.
Next, the company completes the **Bank Verification**. This step requires a micro-deposit flow where two small deposits are made to the company's bank account. The company will leave the onboarding flow and return later to confirm the deposit amount. The micro-deposit flow generally takes 1 - 3 days.
Finally in the **Paperwork** section, the company signs and agrees to the documents Zeal needs to process payroll.
### Note
When the company onboarding flow is completed successfully, Zeal sends this company's information to the webhook you've set for the [Company Onboarding Event](/reference-link/employer-onboarding-event).
***
## Recap
* To onboard a company, company information, bank account, and legal paperwork need to be submitted.
* Bank accounts must be verified through a microdeposit flow which can take up to 2-3 business days.
* Authorization documents must be signed for Zeal to legally begin processing payroll for the company.
* Companies can complete onboarding through the Company Onboarding component.
# FAQs
Source: https://docs.zeal.com/docs/faqs
Here you’ll find some of the most frequently asked questions our new partners have about Zeal.
### Tip
If you have questions not answered below, [Schedule a Demo](https://www.zeal.com/request-a-demo?referrer=%2F) with a member of our team!
**How long should I expect an integration with Zeal to take?**
Using our white-label components, many of our Partners go live with their payroll solution in 1 - 3 weeks. For more custom solutions centered around API integration, the timelines vary depending on the scope of the project. That said, a common strategy is to go live with our white-label components for a faster return on investment, then build out more custom features as adoption of the product grows.
**Do you support all 50 states?**
Yes, we process payroll in all 50 states and all 13,000+ localities.
**Do you offer your services internationally?**
Currently, we do not process payroll outside of the United States. Since the United States has the most complicated tax system in the world, our tax management team focuses their efforts on ensuring that our tax engine is up to date and compliant with even the most obscure tax locality.
**Is Zeal’s branding visible to end users?**
No, Zeal’s white-label components are configured to appear on your domain and to be branded as your own. Your customers will not be aware that Zeal is involved.
**What kind of workers do you support?**
We support both 1099 Contractors and W-2 Employees. In addition, our tax engine is able to support even special employee tax considerations such as agricultural workers, household workers, and more.
**Do you provide end of year tax documents?**
Yes, Zeal provides all end-of-year tax documents such as 1099 and W-2 forms for workers. These are available via the Employer Dashboard, Worker Dashboards, or our APIs.
**How does payroll work?**
Please see our [Introduction to Payroll Runs](/docs/introduction-to-payroll-runs) for a detailed overview of how our system works.
**When does payroll processing begin?**
Payroll processing timelines depends on the speed and disbursement method of the check, but by default payroll processing begins at 2 PM P.T. two bank days before the payroll pay date. Please reference our [Introduction to Payroll Runs](/docs/introduction-to-payroll-runs) for a *Fund Flow* diagram.
**Do you use your own tax engine for gross-to-net calculations?**
Yes, Zeal’s engineers and tax management team audit all federal, state, and local tax agencies to maintain our own comprehensive, in-house tax engine.
**How do you ensure that your tax engine is accurate?**
Zeal has a dedicated tax management team that monitors government authorities for any changes in laws or regulations which would affect tax calculations. Additionally, the team runs a proactive QA process to compare end results against other tax engines and identify any discrepancies.
**As a Partner, what liability do I have for missed payments, improper tax calculations, etc?**
As a Partner, you are not liable for any of the aforementioned scenarios. Employers are ultimately responsible for ensuring their tax documents are up to date. Failure to provide information promptly can result in liabilities which the employer is responsible for. However, as a payroll service we too can make mistakes. In those situations we accept liability so neither you, nor your customers are not adversely affected.
**Do you support payroll migrations?**
Yes, we support payroll migrations both from cloud payroll services and from on-premise software.
# Introduction to Payroll Runs
Source: https://docs.zeal.com/docs/introduction-to-payroll-runs
Before we discuss how to build a payroll product, we'll cover how Zeal's payroll system works. Unlike other payroll providers, where payroll generally must be run on strict cycles, Zeal's system aims to keep things simple. This means that employers (or your system) are only responsible for creating Employee Checks and Contractor Payments. Once these checks and payments are in our system, Zeal processes payroll automatically based on the pay date.
***
## Employee Check Example
The best way to understand how Zeal's system works is with a step-by-step example. The example below is separated into two sections to show the steps an employer (or your system) is responsible for, versus the steps that are automated by Zeal.
### Employer's work
1. An employer creates an Employee Check (**Note:** This can also be automated in several ways. For example: integrating a time and attendance system with our APIs).
2. In the check, the employer defines the work that the employee is being paid for through Shifts.
3. The employer sets the `check_date` (or pay day) for the check and submits it to Zeal.
4. Let's say the employer repeats steps 1 - 3 for two other employees - resulting in three Employee Checks with the same `check_date`.
### Zeal's work
1. Two business days before the `check_date` for our three Employee Checks, Zeal batches all the checks together and sums up the total gross pay + employer taxes.
2. Zeal then debits the gross total from the company's bank account - initiating the payroll processing.
3. Zeal's in-house tax engine performs all the gross-to-net-calculations to determine net pay, how much to withhold for taxes, etc.
4. Over the next two business days, Zeal manages the movement of the money to the employee's bank accounts.
5. By the end of the `check_date` all employees see the net pay in their account.
6. Zeal uses the withholdings to pay out all relevant tax agencies.
7. Zeal shares all information about the payroll run with you via our APIs and via the Company Dashboard and Partner Dashboard.
***
## Fund Flow Breakdown
***
## Contractor Payments Example
Contractor Payments are processed similarly to the Employee Check example above, except there are no gross-to-net calculations or taxes to consider.
### Employer's work
1. An employer creates a Contractor Payment.
2. The employer defines the `amount` the contractor should be paid and the `pay_date` the contractor should receive payment by.
3. Let's say the employer repeats steps 1 - 2 for two other contractors - resulting in three Contractor Payments with the same `pay_date`.
### Zeal's work
1. Two days before the `pay_date` for our three Contractor Payments, Zeal batches all the Contractor Payments together and sums up the total gross pay.
2. Zeal then debits the gross total from the company's bank account - initiating the payroll processing.
3. Over the next two business days, Zeal manages the movement of the money to the contractors bank accounts.
4. By the end of the `pay_date` all contractors see the pay in their accounts.
5. Zeal shares information about the payments made with you via our APIs and via the Company Dashboard and Partner Dashboard.
# Overtime Compliance
Source: https://docs.zeal.com/docs/overtime-compliance
Calculating overtime can be one of the more difficult processes when running payroll. Along with federal regulation surrounding overtime, each state may also have their own regulation. Adding overtime rules to your timekeeping system can take many developer hours. For this, Zeal offers our overtime recommendation engine.
# In this guide
* What is overtime.
* How to report overtime hours to Zeal.
* How to offload overtime calculations to Zeal.
# What is overtime?
Overtime pay is essentially additional compensation that an employee is owed for working extra hours. At the federal level, overtime is defined in the [Fair Labor Standards Act (FLSA)](https://www.dol.gov/agencies/whd/overtime/laws) as any hours worked over 40 in a *workweek* (see [Department of Labor](https://www.dol.gov/agencies/whd/overtime) for definition of a workweek). Any overtime should be paid at a rate of 1.5x the employee’s regular rate of pay.
As with most legislation in the United States, each state may also have its own rules and regulations on overtime. For example a few states, such as Alaska and California, mandate that any hours worked over 8 in a *workday* also be considered overtime.
Finally, there may be industry-specific overtime standards that need to be accounted for. With all this considered, calculating overtime can get complicated.
When accounting for overtime with Zeal there are two options:
1. Calculate overtime hours in your system and report them to Zeal
2. Report regular hours and let Zeal’s overtime recommendation engine do the work
# Report overtime to Zeal
To report overtime hours to Zeal, the first step is to calculate the overtime hours on your system. You’ll need to reference relevant federal, state, and industry-specific regulations, then build rules into your system to convert regular hours to overtime. Alternatively, you could partner with a 3rd party time and attendance system that has this functionality built in.
Once you have the overtime calculations, you can simply report them to Zeal as an `overtime` earning component on a [Shift](/reference/employee-checks/shifts/shift-object).
[Add a shift to an existing check](/reference/employee-checks/shifts/add-shifts-to-check)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/shifts \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"shifts": [
{
"hourly": {
"hours": 8,
"wage": 25
},
"overtime": {
"hours": 2,
"wage": 37.5
},
"workLocationID": "{{workLocationID}}
"time": "2023-01-01T21:00Z"
}
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeCheckID}}"
}
'
```
### Omitting the wage
If you omit the `wage` on an `overtime` earning component, Zeal will take the `default_ot_wage` from the employee object.
# Use Zeal’s overtime recommendations
To make our partners' lives easier, Zeal offers an overtime recommendation engine based on FSLA regulation. It accounts for both federal and state overtime rules.
The first step to take advantage of this feature is to ensure you’re properly reporting a shift’s work location. If an employee only works in one location, nothing is required after onboarding - Zeal will automatically apply the default work location to all shifts. However, if you have employees that work across various jurisdictions, to get the most accurate recommendations, you’ll need to ensure you’re reporting the `workLocationID` of each shift.
### When work locations vary
Check out our guide on Tax Compliance Across Multiple Jurisdictions to learn how to submit work locations for [employees that work in varying jurisdictions](/docs/tax-compliance-across-multiple-jurisdictions#employees-that-work-in-varying-jurisdictions).
Set the employee's `work_week_start`, which defines a fixed, 168-hour period that consists of seven consecutive 24-hour periods. It can start on any day of the week and at any time of day, and it doesn't have to match the calendar week. `work_week_start` should be a timezone specific ISO-8601 date-time.
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/employees \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"employee": {
"employeeID": "{{employeeID}}",
"work_week_start": "2023-01-01T00:00:00.000-07:00"
}
}
'
```
Once this is in place, it's a simple matter of enabling the `flsa_ot_recommendation` flag on any check you want to use overtime recommendations.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employeeCheck \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"flsa_ot_recommendation": true
"shifts": [
...
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2023-03-05",
}
'
```
With this flag enabled, you can submit your shifts with only regular hours.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employeeCheck \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"shifts": [
{
"hourly": {
"hours": 8,
"wage": 25
},
"time": "2023-02-24T17:00"
},
{
"hourly": {
"hours": 9,
"wage": 25
},
"time": "2023-02-25T18:00"
},
{
"hourly": {
"hours": 10,
"wage": 25
},
"time": "2023-02-26T19:00"
},
{
"hourly": {
"hours": 10,
"wage": 25
},
"time": "2023-02-27T19:00"
},
{
"hourly": {
"hours": 8,
"wage": 25
},
"time": "2023-02-28T17:00"
},
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2023-03-05",
"flsa_ot_recommendation": true
}
'
```
Then, when the check is processed, the regular hours will be converted to meet the overtime recommendations.
```bash bash theme={null}
{
"status": 200,
"success": true,
"data": {
"shifts": [
{
"hourly": {
"hours": 8,
"wage": 25
},
"time": "2023-02-24T17:00"
},
{
"hourly": {
"hours": 8,
"wage": 25
},
"overtime": {
"hours": 1,
"wage": 37.5
}
"time": "2023-02-25T18:00"
},
{
"hourly": {
"hours": 8,
"wage": 25
},
"overtime": {
"hours": 2,
"wage": 37.5
}
"time": "2023-02-26T19:00"
},
{
"hourly": {
"hours": 8,
"wage": 25
},
"overtime": {
"hours": 2,
"wage": 37.5
}
"time": "2023-02-27T19:00"
},
{
"hourly": {
"hours": 3,
"wage": 25
},
"overtime": {
"hours": 5,
"wage": 37.5
},
"time": "2023-02-28T17:00"
},
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2023-03-05",
"flsa_ot_recommendation": true
}
}
```
And like that, overtime compliance is managed without having to add complicated rules to your system.
# Errors
Zeal will reject (i.e. fail at processing) any new employee checks with the flsa\_ot\_recommendation attribute during processing if Overtime calculations have already been applied to other employee checks within the same reporting period. In other words, once Zeal has processed and applied Overtime calculations to checks for a given reporting period, no additional checks can be created for that period, as doing so would alter the previously applied calculations.
# Recap
* Overtime pay is essentially additional compensation for extra hours worked.
* Overtime regulation exists at the federal, state, and sometimes even industry level.
* You can calculate overtime hours on your system and report them to Zeal.
* You can alternatively use Zeal’s overtime recommendation engine to convert regular hours to overtime hours.
# Paycard Onboarding (Early Access)
Source: https://docs.zeal.com/docs/paycard-onboarding
Zeal has made it easy to track the progress of a worker's onboarding and provisioning of their paycard.
## Intro
Zeal has made it easy to track the progress of a worker's onboarding and provisioning of their paycard.
**Note: This product is in Early Access. Please reach out to the Zeal team to get access to this Product.**
## In this guide
* How to include the paycard enrollment screen in worker onboarding
* How to track paycard provisioning
## Paycard Enrollment Screen
Every worker that you wish to provision a virtual paycard for must complete paycard enrollment. To include the paycard enrollment page in worker onboarding, you can set `paycard` to `true` when [generating the Contractor Onboarding Link](/reference/contractor-onboarding/generate-contractor-onboarding-link) or when [generating the Employee Onboarding Link](/reference/employee-onboarding/generate-employee-onboarding-link). You can also retrieve the [paycard enrollment screen for employees](/reference/employee-onboarding/create-paycard-enrollment-link) or for [contractors](/reference/contractor-onboarding/create-paycard-enrollment-link) at any time, even after a worker is onboarded.
A worker must agree and consent to agreements on the Paycard Enrollment page.
> **Recommendation:** You can embed the onboarding or individual enrollment link as an iframe or webview in your existing app.
## Paycard Provisioning
Once the agreements are consented to and the onboarding is complete, the paycard has been officially requested and the `paycard_requested` field on the employee or contractor object will be set to `true`. Zeal then runs KYC and/or SSN Verification checks on the worker.
By subscribing to the [Paycard Onboarding Status webhook](/reference/webhooks/paycard-onboarding-status-event), you can track the status of the paycard provisioning:
`requested` (sent when the Paycard Enrollment Screen is completed ⌛) `declined` (KYC and/or SSN Verification checks failed ❌) `provisioned` (KYC and/or SSN Verification checks on the worker are approved and the paycard has been provisioned ✅)
If KYC and SSN Verification is denied or declined, the webhook will send a status of `declined` and `paycard_enabled` field on the employee or contractor object will remain `false`.
If KYC and SSN Verification is approved, the webhook will send a status of `provisioned` and `paycard_enabled` field on the employee or contractor object will be set to `true`. An [update employee](/reference/webhooks/employee-event) or [update contractor](/reference/webhooks/contractor-event-webhook) webhook will also be sent with `paycard_enabled` = `true`.
> **Recommendation:** After listening to the webhook or querying the Employee/Contractor object for the `paycard_enabled` field to ensure the paycard is enabled for this worker, you should prompt the worker to download your app if they have not already. After logging into the app, the worker can access the paycard.
>
> Note: If you have not set up SSO in the mobile app, you should also ensure your worker has created an account in Zeal. Learn more [here](/reference/employee-onboarding/create-account-setup-link).
If the paycard is still in the requested state, but not enabled, or this worker's paycard onboarding has been denied, they will not be able to view their paycard details in their mobile app.
## Handling Failed KYC and SSN Verification
In the scenario that the KYC and/or SSN Verification failed, you can view the statuses using the following fields on the employee or contractor objects:
`kyc_status`holds one of the following values:
`null` `approved` `denied`
`ssn_verification_status` holds one of the following values:
`null` `approved` `declined`
In these cases, an alert will show up on the affected worker in the Company Dashboard. In the case of SSN Verification being declined, an Admin must share an ID Collection link (accessible in dashboard) with the worker to collect identification proving that they possess this SSN. Once Verification is run again and the worker is approved, then the paycard will be provisioned.
## Recap
* Workers must complete the paycard enrollment page which can be included in worker onboarding through UI or API
* Worker must pass KYC and SSN Verification to have their paycard provisioned
# Paycards (Early Access)
Source: https://docs.zeal.com/docs/paycards
Paycards allow workers to get paid faster and have easier access to their funds.
## Intro
Paycards allow workers to get paid faster and have easier access to their funds. Once a worker completes paycard enrollment, a paycard is provisioned to them, and the paycard is now available as a disbursement method for an employee check or contractor payment (e.g. net pay is sent to the paycard). A worker can currently see their paycard details, see transaction history, and transfer funds to an external bank account through the whitelabeled mobile app.
**Note: This product is in Early Access. Please reach out to the Zeal team to get access to this Product.**
## In this guide
* How to include the paycard enrollment screen in worker onboarding
* How to set paycards as a disbursement method on an employee check or contractor payment
* How workers can access paycard details
* How to access paycard information in the Zeal API
## Paycard Enrollment
See [here](/docs/paycard-onboarding) for more paycard enrollment and provisioning information.
## Paycards in Mobile App
Workers can access their paycard details by logging into their worker dashboard in the mobile app and selecting the "Paycard" screen. On this page, workers can:
1. view the paycard details
2. add the card to digital wallet
3. see transaction history
4. transfer balance to an external bank account
5. lock the card
## Paycards API
You can find the Paycard Object details [here](/reference/paycards/paycard-object) and can use the [GET /paycard endpoint](/reference/paycards/get-paycards) to get all Paycard Objects for a company. This can be helpful for programmatically monitoring the status of paycards for workers. The `status` field holds one of the following values: `active`, `suspended`, `terminated`.
## Paycard Disbursement Method
If you wish to have a worker's net pay be sent to their paycard, you can set `disbursement_method` = `paycard` when creating an [employee check](/reference/employee-checks/employee-checks/create-employee-check) or [contractor payment](/reference/contractor-payments/create-contractor-payment). If the disbursement method is set to `paycard`, the net pay amount will be available on the paycard when payroll is processed (e.g. the balance on the paycard will increase by the net pay amount and a new credit transaction will be shown to the worker).
You will receive an error if you try to use `disbursement_method` = `paycard` on a worker that does not have `paycard_enabled` = `true`.
### Real-time Contractor Payments using Triggers
If you want to disburse the funds of a contractor payment earlier than normal processing times, you can facilitate a real-time payment to the worker's paycard by [triggering the contractor payment](/reference/contractor-payments/trigger-disbursement).
The contractor payment must have `disbursement_method` = `paycard` and must still be in the `pending` status. When a pending contractor payment is triggered, it becomes "locked" and uneditable. The funds will be sent to the paycard immediately at time of triggering instead of being sent during normal processing.
## Recap
* Workers must complete the paycard enrollment page which can be included in worker onboarding through UI or API
* Workers can access the Paycard page in the mobile app
* Paycard objects can be retrieved using the API
# Payroll Runs
Source: https://docs.zeal.com/docs/payroll-runs
Through the white-label Company Dashboard we can set up payroll runs rather than working with individual Employee Checks, as in the API.
## In this guide
* How to set up a regular payroll run.
* How to set up an off-cycle payroll run.
* How to edit and submit a payroll run.
***
## Set up
The first step to run payroll through the dashboard is to set up either a regular or off-cycle payroll run. A regular payroll run populates with default values every cycle based on the initial configuration. An off-cycle run can be run at any time, but must be full configured each time.
### Regular payroll run set up
In the Company Dashboard, navigate to **Run Payroll** and click **Set Up**.
On the modal that appears, configure the run settings and add employees to the run.
### Note
If an employee's pay frequency differs from that of the regular payroll run, the employee's pay frequency will be overridden to match that of the run.
Click **Set Up Regular Payroll Run**, review the settings click **Complete setup and run payroll**.
Now that we have our regular payroll setup, we can initiate it ever pay cycle by navigating to the **Run Payroll** page and clicking "Get Started".
On the following page, we'll see a view of our payroll run with defaults based on employee's default wage and pay frequency.
From this page, we can [edit the payroll](/docs/payroll-runs#edit-and-submit-a-run) run or click **Save changes for later**.
### Off-cycle payroll run set up
In the Company Dashboard, navigate to **Run Payroll** and click **Get Started** under the run off-cycle payroll section.
On the following page, we'll select the **Pay frequency**.
Next, select the **Pay period** and **Pay date**, then hit **Continue**.
On the following page, click **Add employees to payroll run**.
In the modal that appears, select the employee or employees you'd wish to pay off-cycle.
On the following page, we'll see a view of our payroll run with defaults based on employee's default wage and pay frequency.
From this page, we can [edit the payroll](/docs/payroll-runs#edit-and-submit-a-run) run or click **Save changes for later**.
## Edit and submit a run
Once a run is set up, we can edit and submit it any time before the cut-off date (2 business days before the pay date).
### Edit a run
In the Company Dashboard, navigate to **Run Payroll** and click either the **Edit payroll** button below the desired section, or click the three dots next to a specific payroll run and click **Edit payroll**.
On the next page, we can review the payroll run and make edits by clicking a pencil icon.
We can also remove an employee from this pay cycle by clicking three dots at the end of the row and deleting the check.
### Submit a run
Once the payroll run is configured as we like, we can click the **Continue** button or the **Preview and submit** tab to get a breakdown of the payroll.
If everything looks good, we can click **Submit**. Payroll will then be automatically finalized and processed two business days before the pay date.
***
## Recap
* There are two kinds of payroll runs: *regular* and *off-cycle*.
* *Regular* payroll runs populate with configured defaults every pay cycle.
* *Off-cycle* payroll can be run at any time, but must be configured each time.
* Once a payroll run is set up, it can be edited from the **Run Payroll** tab.
* You can finalize a payroll run by **Submitting** it or **Save changes for later**.
# Preview Payroll
Source: https://docs.zeal.com/docs/preview-payroll-guide
There are several key use cases for which we would want a breakdown of a payroll before it is processed.
## In this guide
* How to preview upcoming payroll.
* How to preview hypothetical payroll.
***
## Preview Pending Payroll
With either the [Preview Payroll by Check IDs](/reference/preview/preview-payroll-by-check-ids) or [Preview Payroll by Check Date](/reference/preview/preview-payroll-by-check-date), Zeal allows us to get a breakdown of upcoming payroll. For this example, we'll look at viewing upcoming payroll by check date:
### Start a preview payroll job
Call [Preview Payroll by Check Date](/reference/preview/preview-payroll-by-check-date) with the `companyID` and desired `check_date`. This will return a `job_id`.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/preview/checkDate \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"check_date": "2023-01-18"
}
'
```
### Receive updates from the Job Queue Event
When the job is finished processing, Zeal will send you an update via the [Job Queue Event](/reference/webhooks/report-status-change-webhook) webhook.
### Get the results of the job
Include the `job_id` in a call to [Get Preview](/reference/preview/get-preview).
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/preview?job_id={{jobID}}' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Accept: application/json'
```
This will return a JSON object with a `payload` field detailing the breakdown of the payroll.
```bash bash theme={null}
{
"status": 200,
"success": true,
"data": {
"job_id": "12351f1-cc224-4654-81120-39cafeacd8551",
"status": "complete",
"code": 200,
"created_at": "2022-05-04T19:29:39.134Z",
"request_body": {
"companyID": "ae12ffj4141040ac8a3cc3132a3b22l62",
"checks": [
"oq16c5ffccd740e28czz39442f315",
"22reabd897e3345a2ttyfa22b1712be52",
"1337448bd4534cc34tfd783ef1ce8391"
],
"test_mode": false
},
"payload": {
"success": true,
"result": {
"checks": [
{
"gross_pay": 20230,
"net_pay": 46544,
"employer_taxes": 8240,
"employee_taxes": 3856,
"employee_deductions": 0,
"employer_deductions": 0,
"taxes": [
{
"name": "Federal Income Tax",
"codename": "FIT",
"amount": 0
},
{
"name": "Social Security",
"codename": "FICA_SocialSecurity_EE",
"amount": 3125
},
{
"name": "Social Security",
"codename": "FICA_SocialSecurity_ER",
"amount": 3125
},
{
"name": "Medicare",
"codename": "FICA_Medicare_EE",
"amount": 731
},
{
"name": "Medicare",
"codename": "FICA_Medicare_ER",
"amount": 731
},
{
"name": "Medicare Additional",
"codename": "FICA_MedicareAdditional_EE",
"amount": 0
},
{
"name": "Federal Unemployment Tax",
"codename": "FUTA",
"amount": 302
},
{
"name": "State Unemployment Tax",
"codename": "SUTA_GA",
"amount": 4082
}
]
}
"total_employer_taxes": 8240,
"total_employee_taxes": 3856,
"total_employee_deductions": 0,
"total_employer_deductions": 0
}
}
}
}
```
## Preview Hypothetical Payroll
There are some scenarios where it's useful to preview the breakdown of an Employee Check without first submitting it to Zeal. For example, you may want to get a view of what the *net pay* would be for one specific shift in a reporting period. The Preview Check Data endpoint allows us to do just this.
### Preview check data
Submit an Employee Check Object to [Preview Check Data](/reference/preview/preview-check-data) (similar to how data is submitted to the [Create Employee Check](/reference/employee-checks/employee-checks/create-employee-check) endpoint).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/preview/checkData \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2022-01-14",
"shifts": [
{
"time": "2022-01-05T17:00:00Z",
"hourly: {
"hours": 8,
"wage": 25
}
}
],
}
'
```
This will return JSON with a `payload` field detailing the breakdown of the *hypothetical* payroll.
```bash bash theme={null}
{
"success": true,
"data": {
"success": true,
"result": {
"checks": [
{
"gross_pay": "200.00",
"net_pay": "183.58",
"employer_taxes": "26.10",
"employee_taxes": "16.42",
"employee_deductions": "0.00",
"employer_deductions": "0.00",
"taxes": [
{
"name": "Federal Income Tax",
"codename": "FIT",
"amount": "0.00"
},
{
"name": "Social Security",
"codename": "FICA_SocialSecurity_EE",
"amount": "12.40"
},
{
"name": "Social Security",
"codename": "FICA_SocialSecurity_ER",
"amount": "12.40"
},
{
"name": "Medicare",
"codename": "FICA_Medicare_EE",
"amount": "2.90"
},
{
"name": "Medicare",
"codename": "FICA_Medicare_ER",
"amount": "2.90"
},
{
"name": "Medicare Additional",
"codename": "FICA_MedicareAdditional_EE",
"amount": "0.00"
},
{
"name": "Federal Unemployment Tax",
"codename": "FUTA",
"amount": "0.00"
},
{
"name": "State Unemployment Tax",
"codename": "SUTA_AK",
"amount": "10.80"
},
{
"name": "State Unemployment Tax",
"codename": "SUI_AK",
"amount": "1.12"
}
]
}
],
"total_employer_taxes": "26.10",
"total_employee_taxes": "16.42",
"total_employee_deductions": "0.00",
"total_employer_deductions": "0.00"
}
}
}
```
### Include deductions in a hypothetical preview
Preview Check Data never loads an existing Employee Check, so it does not know about deductions already saved against one. To see them in the preview, list them in the `deductions` array along with every shift you want counted — both the shifts already on the check and the ones you are proposing to add. Leaving a saved garnishment out is the most common reason a preview reports a higher net pay than the real check.
You can pass either kind of template ID:
* A 24-character check-scoped deduction template ID from [Get Deduction Template](/reference/employee-checks/deductions/get-deduction-template). These apply only when you also supply a contribution amount.
* A 32-character employee deduction template ID from [List Employee Deduction Templates](/reference/employee-deduction-templates/list-employee-deduction-templates). These apply with their own saved contribution, so `employee_contribution` and `employer_contribution` are optional overrides.
A template is left out of the preview if it is archived, if `check_date` falls outside its effective date range, or if it is a Zeal-managed garnishment. Zeal-managed garnishments are already applied to the preview automatically, so passing one would withhold it twice.
***
## Recap
* There are two ways to preview payroll with Zeal:
* Preview *upcoming* payroll - data that is in Zeal's system awaiting processing.
* Preview *hypothetical* payroll - data that is not submitted to Zeal for processing.
* To preview *upcoming* payroll use the [Preview Payroll by Check IDs](/reference/preview/preview-payroll-by-check-ids) or [Preview Payroll by Check Date](/reference/preview/preview-payroll-by-check-date) endpoints.
* Previewing *upcoming* payroll is an asynchronous process and returns a `job_id`.
* Use the [Job Queue Event](/reference/webhooks/report-status-change-webhook) webhook to receive updates on a job's status.
* Use the [Get Preview](/reference/preview/get-preview) to get the results of a job.
* To preview *hypothetical* payroll use the [Preview Check Data](/reference/preview/preview-check-data) endpoint.
# Quickstart Guide
Source: https://docs.zeal.com/docs/quickstart-guide
In this guide we lead you through a quick, step-by-step example of how to run your first payroll using Zeal's pre-build white-label components. Even if you plan to build fully using the API, this guide gives you a high-level view of how the payroll system works.
If you haven't already, check out our [Introduction to Payroll Runs](/docs/introduction-to-payroll-runs) before continuing with this guide. It gives a conceptual overview of how payroll runs work with Zeal's system.
## In this guide
* How to onboard a Company (employer).
* How to add a Work Location.
* How to onboard an Employee.
* How to set up and submit a Payroll Run.
***
## Onboarding a Company
Zeal represents employers in our system as *Companies*. A Company must first be onboarded before payroll can be run.
Navigate to your Partner Dashboard, ensure that *Test Mode* is enabled, then click **Add company**. In the modal that appears, click **Copy onboarding link**.
Paste the link in a new tab of your web browser, and complete the onboarding flow.
Back on the Partner Dashboard, the newly onboarded company is shown in the main section.
***
## Creating a Work Location
Once the employer is onboarded, you can click on the Company to view the Employer Dashboard as an admin. From here, you can add a Work Location for the Company.
Click the company name.
Navigate to the **Work Locations** page then click **Add a New Location**.
Enter the taxable address where the employee(s) will be working and click **Create**.
***
## Onboarding an Employee
Now that we've added a location our employee(s) will be working at, we can onboard them.
Navigate to the **People** page and click **Add employee**.
Fill the employee information and select the proper Work Location from the dropdown, then click **Add Employee**.
Back on the **People** page, find the Employee and click **Onboarding link** to copy the onboarding link or send it to the worker's email.
Open the link in a new tab to complete the onboarding flow.
***
## Running payroll
Once the employee is onboarded, we can pay them.
Navigate to **Run Payroll** and click **Get Started** under the run off-cycle payroll section.
On the following page, we'll select the **Pay frequency**. Ensure that this matches the *pay schedule* we assigned to our employee.
Next, select the **Pay period** and **Pay date**, then hit **Continue**.
On the following page, click **Add employees to payroll run**.
In the modal that appears, we'll select our employee and hit **Continue**.
On the following page, we'll see a view of our payroll run with defaults based on employee's default wage and pay schedule.
From this page, click **Continue**.
On the final page, click **Submit payroll**.
Once submitted, Zeal will finalize and process the payroll two business days before the pay date.
***
## Recap
* The first step for our payroll solution is to onboard one or more Companies (employers).
* Before onboarding any Employees, a Company must have at least one Work Location.
* To run payroll, first onboard an Employee(s).
* With a Company and Employee(s) onboarded, payroll can be run from the Employer Dashboard.
# Setting up Regular Payroll Run
Source: https://docs.zeal.com/docs/regular-payroll
This guide will explain how to take advantage of Zeal's Regular Payroll Run functionality through the API.
## In this guide
* How to set up a company's payroll settings
* How to get the upcoming date of the next regular payroll run according to company payroll settings
* Create employee checks with given information
***
## Set up Company Payroll Settings
Call [Update Company Information](/reference/companies/update-company-info) with the `payroll_firstCheckDate`, `payroll_schedule`, and `payroll_firstPayPeriodID`. This will return with the company object.
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/companies \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"companyID": "{{companyID}}",
"payroll_firstCheckDate": "2024-08-30",
"payroll_schedule": "weekly",
"payroll_firstPayPeriodID": "6580ce4a3808d60023b4e412"
}
'
```
This will return JSON with the updated [Company Object](/reference/companies/the-company-object).
```bash bash theme={null}
{
"status": 200,
"success": true,
"data": {
"companyID": "{{companyID}}",
"first_name": "Richard",
"last_name": "Hendricks",
"email": "[email protected]",
"business_name": "Pied Piper",
"business_address": "1 Market St.",
"business_city": "San Francisco",
"business_state": "CA",
"business_zip": "94110",
"business_phone": "2025550151",
"mail_address": "1 Market St.",
"mail_city": "San Francisco",
"mail_state": "CA",
"mail_zip": "94110",
"ssn": "22-333-4444",
"ownership_percentage": 25,
"dob": "01/01/1990",
"legal_structure": "ccorp",
"job_title": "CEO",
"address": "1 Ferry Building",
"city": "San francisco",
"state": "CA",
"zip": "94105",
"payroll_firstCheckDate": "2024-08-30",
"payroll_schedule": "weekly",
"payroll_firstPayPeriodID": "6580ce4a3808d60023b4e412"
}
}
```
## (Optional) Set up Employee with Regular payroll settings
This is optional because these settings are used in the Zeal UI when generating payroll runs. If you use the API to create employee checks, you do not need these fields.
Set the following fields on an [Employee](/reference/employees/the-employee-object):
* Set `is_salary` = `true`
* Set `salary` field on the Employee
* **Reminder: the`salary` field is required IF `is_salary`=true**
You can set `is_regular` = `true` if you'd like this worker to show up automatically in your on-cycle payroll runs in the Zeal UI as well.
## Get upcoming Regular Payroll Run date
At any time, you can call the ["Get Upcoming Regular Payroll" endpoint](/reference/employee-checks/payroll-run/get-upcoming-regular-payroll) to get the upcoming "regularly" scheduled check date and associated reporting period information.
```bash bash theme={null}
curl --request GET \
--url https://api.zeal.com/payroll/regular?companyID={{companyID}} \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json'
```
This will return Reporting Period and Check Date information.
```bash bash theme={null}
{
"status": 200,
"success": true,
"data": {
"reportingPeriodID": "6580ce4a3808d60023b4e412",
"start": "2024-08-24",
"end": "2024-08-30",
"checkDate": "2024-08-30"
},
}
```
## Create Employee Checks
You can now call the [Create Employee Check](/reference/employee-checks/employee-checks/create-employee-check) endpoint, with the check date and reporting period information from the previous endpoint (see [here](/docs/employee-checks-guide) for more details on how to create an Employee Check). Include a flat earning component with the appropriate `hours` and `amount`.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employeeCheck \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"approval_required": false,
"disbursement": {
"method": "direct_deposit"
},
"shifts": [
{
"flat": {
"hours": 80,
"amount": 2500
},
"time": "2023-02-24T15:00"
}
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2024-08-30"
}
'
```
With the check in our system, it will automatically be batched and begin processing 2 days before the `check_date`.
### Note
If you create employee checks for "is\_regular" employees through the API, you will not necessarily see payroll runs in the UI.
# Reports
Source: https://docs.zeal.com/docs/reports-guide
One of the best features of Zeal is our reporting.
## In this guide
* How to start a report job.
* How to receive job updates.
* How to get the results of a job.
* How to download reports from the Company Dashboard.
* How to include the Reports stand-alone component in your application.
***
## API
### Start a report job
Reports are processed asynchronously with a job queue. To initiate a job call [Create Payroll Journal Report](/reference/reports/create-payroll-journal-report). This will return a `job_id`.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/reports/payroll-journal \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"start_date": "2022-01-01",
"end_date": "2022-03-28",
"companyID": "{{companyID}}",
"media_type": "csv"
}
'
```
### Receive updates from the Job Queue Event webhook
When the job is finished processing, Zeal will send you an update via the [Job Queue Event](/reference/webhooks/report-status-change-webhook).
### Get the results of a job
Include the `job_id` in a call to [Get Job Status](/reference/reports/get-job-status).
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/reports?job_id=ID&companyID={{companyID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
The returned JSON will include a `payload` field which may be used to download the report.
```bash bash theme={null}
{
"status": 200,
"success": true,
"data": {
"job_id": "7g88a4e0-f2a0-4dc0-9a1c-215e083de5eb",
"status": "complete",
"created_at": "2022-03-25T18:52:43.138Z",
"request_body": {
"start_date": "2022-01-01",
"end_date": "2022-03-28",
"company_id": "fc235f012bae46aa8a082f357715bcfa",
"media_type": "csv",
"has_live_key": true,
"report_format": "payroll_journal"
},
"payload": "https://api.zeal.com/reports/downloads/7g88a4e0-f2a0-4dc0-9a1c-215e083de5eb"
}
}
```
***
## White-Label
### Company Dashboard
If you are using our white-label Company Dashboard, reports can be accessed through the **Reports** page.
Navigate to the **Reports** page and click the **Payroll Journal** card.
Fill the information on the following page and then click **Generate**. A success alert will appear indicating that the browser will automatically download the report when it is ready in a few moments. Please ensure [pop-ups](https://support.google.com/chrome/answer/95472?hl=en\&co=GENIE.Platform%3DDesktop) are enabled in the browser.
Once the report has downloaded, we can open it to view the payroll journal.
### Embedding the Reports Page
If you’ve built your own custom dashboards using our APIs, you can embed the Reports white-label component directly in your dashboard.
Call [Generate Reports Link](/reference/zeal-components/generate-reports-link).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/authLinks/reports \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}"
}
'
```
Embed the link in your application through and iframe or open it up in a new tab.
***
## Recap
* Reports are process asynchronously using a job queue.
* You can subscribe to the [Job Queue Event](/reference/webhooks/report-status-change-webhook) webhook for updates on a job.
* Once your job has been process, get the result with the [Get Job Status](/reference/reports/get-job-status) endpoint.
* Reports can be downloaded on demand from the **Reports** page of the Company Dashboard.
* Use the [Generate Reports Link](/reference/zeal-components/generate-reports-link) endpoint to include the **Reports** page as a stand-alone component in your application.
# Payroll
Source: https://docs.zeal.com/docs/running-payroll-guides
As discussed in our Introduction to Payroll Runs Guide, Zeal's payroll system works differently from some traditional payroll providers.
## In this section
* How to pay W-2 Employees.
* How the white-label represents Payroll Runs.
* How to add Deductions to an Employee Check.
* How to preview payroll.
* How to access reports such as payroll journals.
* What tax requirements are and how to submit them.
* How to pay 1099 Contractors.
## Employee Checks
Employee Checks represent all the information that Zeal needs to process payroll for W-2 employees. Employee Checks hold a lot of important data and configuration such as the `check_date`, `reporting_period`, and `shifts`.
Learn more about [Employee Checks](/docs/employee-checks-guide).
## Payroll Runs
Payroll Runs are an abstraction used in Zeal's white-label UI for a familiar user experience. Payroll Run group Employee Checks together before they are processed to provide easier viewing and editing functionality.
Learn more about [Payroll Runs](/docs/payroll-runs).
## Deductions
Deductions account for additional withholdings such as 401K contributions and garnishments. Individual Deductions are created using Deduction Templates that define the rules to be followed.
Learn more about [Deductions](/docs/deductions-guide).
## Preview Payroll
The option to preview payroll before it begins processing informs many important use cases. Zeal system allows users to view *upcoming* payroll or *hypothetical* payroll.
Learn more about [previewing payroll](/docs/preview-payroll-guide).
## Reports
Zeal offers many great out-of-the-box reports such as payroll journals, labor allocation reports, and worker summary reports. Reporting is an invaluable piece of a payroll system that inform many administrative processes.
Learn more about [Reports](/docs/reports-guide).
## Tax Requirements
Tax requirements are documents that an employer must submit in order for Zeal to properly pay and report taxes on their behalf. Zeal provides a frictionless way for employers to submit Tax Requirements directly to our Tax team.
Learn more about [Tax Requirements](/docs/tax-requirements-guide).
## Contractor Payments
Contractors can be paid with ease given that there are no payroll taxes that need to be withheld. Simply tell us the `amount` and the `pay_date` and Zeal will handle the rest.
Learn more about [Contractor Payments](/docs/contractor-payments-guide).
# Tax Compliance Across Multiple Jurisdictions
Source: https://docs.zeal.com/docs/tax-compliance-across-multiple-jurisdictions
Managing payroll taxes becomes difficult as your workforce grows - especially if you have employees across multiple tax jurisdictions. Say an employee works half a pay cycle in New York and the other half in New Jersey. Should you withhold income tax for both states? Are there reciprocity agreements that apply? Thankfully, Zeal’s tax engine already accounts for all these cases.
# In this guide
* What determines how payroll taxes are withheld.
* How to manage employees that live in one jurisdiction but work in another.
* How to manage employees that work across multiple jurisdictions.
* How to submit tax requirements for employers.
# Payroll taxes
Payroll taxes are taxes paid by employers and employees on wages, tips, and salaries. This includes federal and state income taxes, Social Security and Medicare, as well as local taxes such as for school districts.
Technically, these taxes are all reconciled during end-of-year filings (most of us in the United States know the joys of tax season). However, to avoid payment defaults, the government mandates that payroll taxes be estimated, withheld, and remitted to the proper tax agencies throughout the year. This is one of the core services that Zeal provides.
# Calculating payroll taxes
In order to properly calculate payroll taxes Zeal’s tax engine needs an employee's:
* **Compensation information** - wages, tips, and/or salary earned.
* **Tax parameters** - what deductions are claimed on the withholding statement(s) (W-4 form).
* **Residential address** - where the employee lives.
* **Work location** - where work is completed.
Zeal enforces that all this information is collected before an employee can be onboarded to the system (see [employee onboarding](/docs/employee-onboarding-guide) for more details). For information that may vary between pay periods, Zeal will collect default values to fall back on.
An employee’s tax parameters and residential address are generally fixed. They may need to be updated on a one-off basis, but don’t vary shift to shift. So to remain compliant across multiple jurisdictions, we really just need to onboard correctly and then submit work locations along with compensation information.
# Employees that live and work in different jurisdictions
Having an employee that lives in one jurisdiction, but works in another may seem like a difficult hurdle. However, it’s actually a problem that’s handled when onboarding an employee to Zeal.
## Residential address and default work location
Zeal requires a valid **address** and **work location** in order to create an employee. The `workLocationID` will point to the employee’s *default* work location. Later, we’ll discuss how to override this for employees that work across varying jurisdictions.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
[Create an employee](/reference/employees/create-employee)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data-raw '
{
"new_employees": [
{
"overtime_rate": 1.5,
"double_time_rate": 2,
"autopilot": {
"autopilot_on": false
},
"is_943": false,
"is_scheduleH": false,
"email": "[email protected]",
"first_name": "Richard",
"last_name": "Hendricks",
"title": "CEO",
"default_pay_schedule": "semimonthly",
"default_wage": 50,
"workLocationID": "{{workLocationID}}",
"start_date": "2022-01-01",
"dob": "1985-05-25",
"ssn": "123456789",
"phone_number": "1234567890",
"address": "1 Market St.",
"city": "San Francisco",
"state": "CA",
"zip": "94110"
}
],
"companyID": "{{companyID}}"
}
'
```
## Setting tax parameters
If you use Zeal’s [white-label employee onboarding component](/docs/employee-onboarding-guide#white-label), the UX will ensure that the proper tax parameters are gathered. Otherwise, you can get and set the tax parameters based on the living state and working state(s).
[Generate employee tax parameter definitions](/reference/employee-onboarding/generate-employee-tax-parameter-definitions)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees/getTaxParameterDefinitions \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"jurisdictions": [
"US",
"CA"
]
}
'
```
[Set employee tax parameters](/reference/employee-onboarding/set-employee-tax-parameters)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employees/setTaxParameters \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"employeeID": "{{employeeID}}",
"companyID": "{{companyID}}",
"federalParameters": [
{
"code": "FILINGSTATUS",
"jurisdiction": "US",
"value": "H"
}
],
"stateParameters": [
{
"code": "FILINGSTATUS",
"jurisdiction": "CA",
"value": "H"
},
{
"code": "REGULAR_ALLOWANCES",
"jurisdiction": "CA",
"value": "1"
},
{
"code": "SUTA_CA_EXEMPT",
"jurisdiction": "CA",
"value": "NO_REPORTING"
}
]
}
'
```
# Employees that work in varying jurisdictions
It can be a little trickier to account for employees who may not always work in the same location. Many workers on Zeal’s system work for large staffing companies, and as such, may even work in several locations within the same pay period!
## Include the work location in a shift
To handle this, Zeal allows you to submit a work location along with any shift in the employee check object.
[Create an employe check](/reference/employee-checks/employee-checks/create-employee-check)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/employeeCheck \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"approval_required": false,
"disbursement": {
"method": "direct_deposit"
},
"shifts": [
{
"hourly": {
"hours": 8,
"amount": 25
},
"workLocationID": "{{workLocationID}}
}
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeID}}",
"reportingPeriodID": "{{reportingPeriodID}}",
"check_date": "2022-01-14"
}
'
```
[Or add a shift to an existing check](/reference/employee-checks/shifts/add-shifts-to-check)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/shifts \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"shifts": [
{
"hourly": {
"hours": 8,
"amount": 25
},
"workLocationID": "{{workLocationID}}
}
],
"companyID": "{{companyID}}",
"employeeID": "{{employeeCheckID}}"
}
'
```
### Omitting the work location
If you omit a `workLocationID` Zeal, will fallback to the workLocationID on the employee object gathered during onboarding.
With the work location reported for every shit, Zeal can calculate taxes for every jurisdiction an employee works.
# Submitting employer tax requirements
As you onboard employees in different jurisdictions, you’ll need to ensure that all the employer tax requirements have been submitted. These requirements give Zeal the information and legal permission that we need to properly file taxes in all jurisdictions the employer operates in.
This information can be submitted in the Tax Setup page. When you enter the Tax Setup page, you'll see alerts for any missing requirements the employer has.
### Admin/Employer Dashboard
If you are using our white-label Employer Dashboard, employers can access their tax requirements through the Taxes page.
1. Navigate to the **Taxes** page.
2. At the top of the page, employers can see any missing requirements
3. Employers can also search by state and locality to proactively submit tax requirements.
### Embedding the Taxes Page
If you’ve built your own custom dashboards using our APIs, you can embed the Taxes component directly in your dashboard.
1. Call [Generate Employer Taxes Page Link](/reference/zeal-components/generate-company-taxes-page-link)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/authLinks/taxes \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}"
}
'
```
2. Embed the link in your application through and iframe or open it up in a new tab.
# Recap
* Zeal automatically withholds and remits taxes to the proper tax agencies.
* Zeal calculates payroll taxes based on an employee’s compensation, tax parameters, residential address, and work location.
* All required information for an employee that lives in one location but works in another is gathered during onboarding.
* To manage workers with varying work locations, you can submit a workLocationID as part of the shift object For each jurisdiction that you have employee’s, employer tax requirements must be submitted to give Zeal the information and permission to file taxes to that jurisdiction.
* Tax requirements can be submitted via the Tax Setup page which can be accessed through the Partner Dashboard, Employer Dashboard, or embedded.
# Tax Requirements
Source: https://docs.zeal.com/docs/tax-requirements-guide
Tax requirements are documents that an employer must submit in order for Zeal to properly pay and report taxes on their behalf. Which documents an employer must submit depends on the state(s) and localities in which they have employees. Thankfully, these requirements can be easily tracked and submitted with Zeal.
## In this guide
* How to view a companies outstanding requirements.
* How to submit tax requirements.
* How to embed the Taxes page in your application.
***
## Viewing tax requirements
### Requirements on the Company Object
Zeal's system automatically tracks the tax requirements for an employer and updates the `requirements` field of their [Company Object](/reference/companies/the-company-object) when new documents should be submitted.
Call [Get Company Information](/reference/companies/get-company-information).
```bash bash theme={null}
curl --request GET \
--url https://api.zeal.com/companies \
--header 'accept: application/json'
```
This will return a JSON object containing a `requirements` field.
```bash bash theme={null}
{
"success": true,
"data": {
// ...
"requirements": [
{
"companyID": "1234567890",
"type": "state_payroll_tax_number",
"state": "AZ",
"id": "33472873692",
"name": "State Payroll Tax No. required",
"description": "John Doe is working in AZ for which the state payroll number has not been submitted.",
"deadline": null
},
{
"companyID": "1234567890",
"type": "local_number",
"state": "PA",
"name": "Local or Miscellaneous Tax Information Required",
"description": "You are employing employee(s) that are working in PA for which the Local/Miscellaneous Tax Information has not been submitted (LIT_PA_LST_PENN-TRAFFORD_SD)."
}
]
}
}
```
### Alerts on the Taxes page
On the Taxes page, an alert appears for any missing requirements.
## Submitting tax requirements
### Admin/Employer Dashboard
If you are using our white-label Company Dashboard, employers can access their tax requirements through the Taxes page.
Navigate to the **Taxes** page.
At the top of the page, employers can see any missing requirements
Employers can also search by state and locality to proactively submit tax requirements.
### Embedding the Taxes Page
If you've built your own custom dashboards using our APIs, you can embed the Taxes component directly in your dashboard.
Call [Generate Employer Taxes Page Link](/reference/zeal-components/generate-company-taxes-page-link)
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/authLinks/taxes \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"partnerID": "{{partnerID}}",
"companyID": "{{companyID}}"
}
'
```
Embed the link in your application through and iframe or open it up in a new tab.
***
## Recap
* Tax requirements are documents that an employer must submit in order for Zeal to properly pay and report taxes on their behalf.
* Tax requirements can be view under the `requirements` field of the [Company Object](/reference/companies/the-company-object) or from the **Taxes** page.
* Tax requirements can be submitted through the **Taxes** page.
* The **Taxes** page is included in the Employer Dashboard, but can also be embedded in your application as a stand-alone component.
# Time & Attendance Integration
Source: https://docs.zeal.com/docs/time-attendance-integration
One of the best features of Zeal is how easily it can be integrated with other systems in order to automate traditionally manual processes.
### **Tip**
Watch the [video demo](https://www.loom.com/share/ad92a80e6e924a379b45c74ac4a21046) to get an overview of the integration before starting the guide!
One of the best features of Zeal is how easily it can be integrated with other systems in order to automate traditionally manual processes. For example, many of our partners connect Zeal's APIs with a time and attendance system in order to automate the submission of Employee Checks.
While there are many things you can do with a time and attendance system, this guide will get us started by walking through a simple integration with a popular free time-keeping app, [Clockify](https://clockify.me/).
## In this guide
* How to set up a Clockify account.
* How to stand up a server to convert Clockify Time Entry data to Zeal Employee Checks.
* What the code does.
***
## Clockify account setup
First, we'll create a Clockify account and generate an API key.
Navigate to the [Clockify Signup Page](https://app.clockify.me/tracker) and follow the steps to create an account. Once your account is created, navigate to your [user settings](https://app.clockify.me/user/settings), scroll to the bottom, and click **Generate** under the API section.
Store the API Key for the next step.
## Stand up the server
In this step, we'll set up a Node (Express) server to receive incoming data from Clockify. In order for webhooks from Clockify to reach our local server, we'll need to expose it to the internet. There are many ways of doing this, but we'll be using [ngrok](https://ngrok.com/).
### Associate a Zeal employee with our Clockify account
The first thing we'll want to do before we get our server up and running, is establish a connection between our Zeal Employee and our Clockify Account. In a production application, we'd establish a process to do this automatically whenever a new employee onboards to Clockify, but for now we'll do it manually.
Using your Clockify API key from the previous step, run the following curl command.
```bash bash theme={null}
curl -H "content-type: application/json" -H "X-Api-Key: {{YOUR API KEY}}" -X GET https://api.clockify.me/api/v1/user
```
Use the `id` field from the response to add an `external_id` to your Zeal Employee.
```bash bash theme={null}
curl --request PATCH \
--url https://api.zeal.com/employees \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"employee": {
"employeeID": "{{employeeID}}",
"external_id": "{{clockifyUserID}}"
},
"companyID": "{{companyID}}"
}
'
```
Now that our Employee is linked with our Clockify Account we can set up the server.
### Set up an Express server
Clone our example repository at [https://github.com/zeal-corp/zeal-clockify-integration-example](https://github.com/zeal-corp/zeal-clockify-integration-example).
```bash bash theme={null}
git clone [email protected]:zeal-corp/zeal-clockify-integration-example.git
```
Create a `.env` in the root directory and add your Zeal Test API Key and the Company ID.
```bash bash theme={null}
echo "ZEAL_TEST_KEY=YOUR TEST KEY\nZEAL_COMPANY_ID=YOUR COMPANY ID" >> .env
```
### Note
For the scope of this example, we'll only process time entries for one company so use the ID of the company containing the Zeal Employee from the previous step.
With our environmental variables configured, we can start the server by running `npm run dev`. You should see the following output in your terminal.
```bash bash theme={null}
$ 🦓🦓🦓 [SERVER_START]: Server is running at http://localhost:3000
```
### Expose the server to the public web using ngrok
Next we'll need to install ngrok and configure our ngrok authorization token. Follow the instructions [here](https://ngrok.com/download) to do so.
Once the configuration of ngrok is complete we can run the following line in the terminal to expose our Express server to the internet.
```bash bash theme={null}
ngrok http 3000
```
An ngrok window will open in your terminal and display the following:
```bash bash theme={null}
Session Status online
Account Your Name (Plan: Free)
Version 3.0.7
Region South America (sa)
Latency 157ms
Web Interface http://127.0.0.1:4040
Forwarding https://83d8-193-37-252-220.sa.ngrok.io -> http://
Connections ttl opn rt1 rt5 p50 p90
2 0 0.01 0.00 5.20 5.39
HTTP Requests
----------------
```
Copy the URL displayed next to the `Forwarding` field and store it for use in the next step. **Note:** don't stop ngrok or your Express server.
```
Forwarding https://83d8-193-37-252-220.sa.ngrok.io
```
### Add a webhook URL in Clockify
Now we want to configure our webhook in our Clockify dashboard.
Navigate back to the [user settings](https://app.clockify.me/user/settings) in Clockify and click **Manage webhooks** at the bottom.
On the following page click **Create New** in the top right corner. In the modal the appears, as shown below, set the **Endpoint URL** to the ngrok URL from the previous step + `/time-entry/timer-stopped` (the path in our controller).
Set the **Event** to *Timer stopped (me)* then hit **Create**.
### Testing the webhook
Now for the fun part: testing that it works!
Navigate to the [time tracker](https://app.clockify.me/tracker) in Clockify and click the "Project" button.
Click **Create new project**, give your project a name then hit **Create**.
Now click the **Start** button, wait *at least 18 seconds*, then hit the **Stop** button.
### Note
You must wait at least 18 seconds because shifts are measured on an hourly basis. We must have a time duration that's enough to be rounded to at least .01 hours otherwise we'll receive an error in the logs.
Clicking the **Stop** button will trigger the *Timer Stopped (me)* Event in Clockify and the data will be POSTed to your Express server. The time entry data represented in JSON looks similar to this:
```bash bash theme={null}
{
id: '{{timeEntryId}}',
description: '',
userId: '{USERID}',
billable: true,
projectId: '{{projectId}}',
timeInterval: {
start: '2022-09-09T21:00:59Z',
end: '2022-09-09T21:01:06Z',
duration: 'PT7S'
},
workspaceId: '{{workspaceId}}',
isLocked: false,
hourlyRate: null,
costRate: null,
customFieldValues: [],
type: 'REGULAR',
kioskId: null,
currentlyRunning: false,
project: {
name: 'Blank Project',
clientId: '',
workspaceId: '{{workspaceId}}',
billable: true,
estimate: { estimate: 'PT0S', type: 'AUTO' },
color: '#FF9800',
archived: false,
clientName: '',
duration: 'PT7S',
note: '',
activeEstimate: 'NONE',
timeEstimate: {
includeNonBillable: true,
estimate: 0,
type: 'AUTO',
resetOption: null
},
budgetEstimate: null,
id: '{{projectId}}',
public: false,
template: false
},
task: null,
user: {
id: '{USERID}',
name: '{{yourName}}',
status: 'ACTIVE'
},
tags: []
}
```
The time entry data is received by our server and converted into a Shift that we then submit as an Employee Check to Zeal.
If everything was successful you should see a `201` HTTP response in the ngrok server.
```bash bash theme={null}
HTTP Requests
-------------
POST /time-entry/timer-stopped 201 Created
```
### Check the logs
Additionally, we can check the Clockify webhook logs to verify that a check was created.
Navigate back to the [user settings](https://app.clockify.me/user/settings) in Clockify and click **Manage webhooks** at the bottom.
On the next page, click **My Timer Stopped**. This will open the logs for this webhook.
In the logs, we should see a successful entry. If we click the timestamp, we can view the response from our server with the Zeal `employeeCheckID`.
Finally, we can call [Get Employee Check by ID](/reference/employee-checks/employee-checks/get-employee-check-by-id) to view the Employee Check.
```bash bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/employeeCheck?companyID={{companyID}}&employeeCheckID={{employeeCheckID}}' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
Amazing! We now have a fully automated way of creating/updating Employee Checks in Zeal. Now, let's take a peek at the code that got us here.
## Code review
The app (server) has two main sections that would be helpful to review:
1. The initial configuration on startup.
2. The handler for the `/time-entry/timer-stopped` route.
### App configuration
Looking into `src/config/app.config.ts` we can see that there are several variables that the app is dependent on that are being configured.
```bash bash theme={null}
// snippet from app.config.ts
const port = process.env.PORT || 3000;
let zealClient: ZealClient;
let companyID: string;
let defReportingPeriods: any[];
async function configureAppVars() {
if (!process.env.ZEAL_TEST_KEY || !process.env.ZEAL_COMPANY_ID) {
throw Error(
"Missing Configuration: Please add your ZEAL_TEST_KEY and ZEAL_COMPANY_ID in your .env file."
);
} else {
zealClient = ZealFactory.fromDefaultClient(process.env.ZEAL_TEST_KEY);
companyID = process.env.ZEAL_COMPANY_ID;
defReportingPeriods = await getDefReportingPeriodsByPayday(
"Fri",
zealClient,
companyID
);
}
}
```
### **Note:**
In a production app, we'd likely rely on a database to store data such as the `companyID` and `defReportingPeriods`, but we wanted to keep this app as simple as possible so we chose to use this workaround.
Let's walk through the ones that may not be readily apparent:
1. `zealClient`: this is basically an wrapper for the commonly used [axios library](https://axios-http.com/docs/intro) for making HTTP requests. This Zeal module found in `src/services/zeal` simply helps us make requests to Zeal's API.
2. `companyID`: nearly all requests to Zeal's API require a company ID to be passed as a parameter so we initialize that here for later use.
3. `defReportingPeriods`: this establishes a list of Reporting Periods that our app can reference internally, instead of having to make a call to the [Zeal API](/reference/employee-checks/reporting-periods/get-reporting-period-by-date-range) every time we receive Time Entry data from Clockify.
### **Tip:**
You can see the reporting periods the app is establishing by visiting [http://localhost:3000/reporting-periods](http://localhost:3000/reporting-periods) after the app starts.
A few more words on `defReportingPeriods`:
Every Zeal Employee Check should be scoped to a particular Reporting Period that describes when the work was completed. Zeal supports every potential Reporting Period for a given calendar year. Since our app is determining the Reporting Period automatically, based off the time entry data we get from Clockify, it's useful to filter the all potential Reporting Periods down to only the ones that fit our desired pay schedules.
For the purpose of this example, the logic found in `src/config/defReportingPeriods.config.ts` defines a ruleset that employees should be on a weekly pay schedule and that the Reporting Periods should end one week before any given payday.
### Note
For Example:
If the payday is "*Fri*", then Reporting Period for a 2022-09-30 check date should be 2022-09-17 - 2022-09-23.
### Time Entry Controller
The main functionality of the app is defined in `src/controllers/timeEntry.controller.ts`. Looking into the code, we can see there are 3 main process the app performs whenever it receives Time Entry data from Clockify:
```bash bash theme={null}
// snippet from timeEntry.controller.ts
export async function handleTimeEntry(
req: Request,
res: Response,
next: NextFunction
) {
try {
const employee = await findEmployeeByClockifyID(req.body.userId);
const reportingPeriod = findReportingPeriod(req.body.timeInterval?.start);
const check = await createOrUpdateEmployeeCheck(
req,
employee,
reportingPeriod
);
res
.status(201)
.json({ success: true, employeeCheckID: check.employeeCheckID });
} catch (e) {
return next(e);
}
}
```
1. The app pulls the Clockify `userId` from the request body and makes a call to Zeal to find an Employee with a matching `external_id` field.
```bash bash theme={null}
// snippet from timeEntry.controller.ts
export async function findEmployeeByClockifyID(clockifyUserId: string) {
const employees = await zealClient
.getAllEmployees({
companyID,
external_id: clockifyUserId,
});
if (employees.length) {
return employees[0];
} else {
throw new ResourceNotFoundException("Zeal Employee");
}
}
```
2. It pulls the `start` time from the request body and searches our `defReportingPeriods` to find the Reporting Period that the `start` time falls within.
```bash bash theme={null}
// snippet from timeEntry.controller.ts
// Note: this helper function is called by #findReportingPeriod
export function findMatchingReportingPeriod(
reportingPeriods: any[],
startDate: string
): any {
const reportingPeriod = reportingPeriods.find((rp) => {
const isDateWithinRP = startDate >= rp.start && startDate <= rp.end;
return isDateWithinRP;
});
return reportingPeriod;
}
```
3. It checks if there is an existing Employee Check for this Reporting Period and then makes a request to Zeal to either create a new check or update the existing check.
```bash bash theme={null}
// snippet from timeEntry.controller.ts
export async function createOrUpdateEmployeeCheck(
req: Request,
employee: any,
reportingPeriod: any
) {
/* #buildShift takes the time entry data and converts it
to a Zeal Shift Object */
const hourlyShift = buildShift(req.body.timeInterval);
const existingCheck = await getAnyExistingCheck(
employee.employeeID,
reportingPeriod.reportingPeriodID
);
if (!existingCheck) {
return await createCheck(employee.employeeID, reportingPeriod, hourlyShift);
} else {
return await updateCheck(existingCheck.employeeCheckID, hourlyShift);
}
}
```
### Summary
Ultimately, there is a bit more complexity involved in the app, but this is the main functionality. We hope that this overview gives you a great foundation to explore and expand the application as you see fit. Happy hacking!
## Recap
As you can see, with this fairly simple integration, we are able to automate the submission of time entry data that a payroll admin may traditionally have to input manually or through CSV upload. We hope that this dive into managing time and attendance data with Zeal inspires you to develop new and creative ways to improve your payroll systems. We at Zeal are excited to partner with you every step of the way!
# What is Zeal?
Source: https://docs.zeal.com/docs/what-is-zeal
Zeal makes it faster, easier, and better for companies to build payroll into their products.
Tip: Don't want to sift through docs? [Schedule a demo](https://www.zeal.com/contact-us) and let us give you a guided tour of everything Zeal has to offer!
Zeal makes it faster, easier, and better for companies to build onboarding and payroll into their products. Our automated, flexible solutions reduce operational costs, improve retention, and help companies create more revenue.
While Zeal provides turnkey custom branded mobile apps, integrations, and an admin dashboard there’s also an API and White-label Components for more flexibility and customization. However you choose to implement, Zeal is here to help. We are more than just software, we are people dedicated to your success.
***
## Why embedded payroll?
You may be thinking “why should embed payroll"? If you're company is thinking about how to deliver a payroll experience the simple answer is that building payroll is hard. Getting taxes, compliance, and payments right across every worker, every payday, every jurisdiction, every regulation, and every edge case is simply very challenging. But delivering payroll in your own brand that gets that right gives you the ability to make more money and improve retention.
**Onboarding.** It’s possible to onboard workers with paper forms. It’s also possible to onboard in online forms and PDFs. But if you want a solution that can onboard workers remotely, in just a few minutes, without any effort from your staff – then you’ll want embedded payroll.
**Payroll**. You can pay workers with checks, or even use payroll software to make running payroll easier. But if you want to make sure that you’re calculating wages correctly, paying workers quickly, and maintaining compliance – then you’ll want embedded payroll.
**Automation.** For decades companies have operated with experienced people handling operations. And while people are still required to run payroll, the mundane work can be automated. Companies who want to lower operating costs and scale easily are using embedded payroll to handle routine tasks.
**Mobile app.** For most businesses, workers are the most expensive cost and the most important part of their success. The best companies care about creating the best worker experience. A mobile app improves worker retention by giving workers the ability to onboard, access pay, see pay history, edit information, and more whenever and wherever they need to.
***
## Why Zeal?
Zeal strives to be the best embedded payroll company. Some differentiators between Zeal and others are:
* Zeal creates payroll infrastructure built from the ground up by us. We don't wrap legacy providers choosing instead to build critical pieces of our infrastructure ourselves including own tax, compliance, and payroll calculation engines. We started after struggling with running payroll for our own company.
* Zeal can scale easily. We support unlimited workers per FEIN (employer) while other payroll providers cannot. We also support many FEINs (employers) with a few workers each. Whatever your situation is we can support it.
* We support many different types of workers and worker payments. W-2 and 1099 worker payments and compliance. Pay frequencies including daily, weekly, bi-weekly, semi-monthly, monthly, and on-demand payments. We support a wide range of payment methods including direct deposit, instant pay, physical checks, paycards, and more.
* We want workers to have the best experience possible, and allow you to deliver the worker experience to them in your brand. We do the work, you get the credit.
* We want you to be successful. We are partners in your success and have dedicated support including help from our tax, compliance, payments, and product experts.
# Work Locations
Source: https://docs.zeal.com/docs/work-locations-guide
Before onboarding a W-2 Employee, we'll need to specify where the employee will be working. This is known as a Work Location and is important for taxation. A Work Location is often reused for multiple employees but may also be used by only one employee (sometimes the case for remote employees).
### Note
Work Locations aren't required to onboard 1099 Contractors due to their taxable status. To learn how to onboard contractors, reference our [Contractor Onboarding Guide](/docs/contractor-onboarding-guide).
## In this guide
* How to create a Work Location using the API
* How to create a Work Location from the white-label Company Dashboard component
***
## API
### Verify the address
Call [Resolve Taxable Location](/reference/taxable-locations/resolve-taxable-location) to verify that an address is taxable.
### Note
Remember to replace the placeholders such as `{{testApiKey}}` in the code samples below.
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/taxableLocations \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"street1": "941 Newell Rd.",
"street2": "",
"city": "Palo Alto",
"state": "CA",
"zip": "94303"
}
'
```
### Add a Work Location
Use the `taxableLocationID` returned in the previous step to call [Create Work Location](/reference/work-locations/create-work-location).
```bash bash theme={null}
curl --request POST \
--url https://api.zeal.com/workLocations \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}' \
--header 'Content-Type: application/json' \
--data '
{
"taxableLocationID": "{{taxableLocationID}}",
"companyID": "{{companyID}}",
"name": "Main Office"
}
'
```
## White-Label
### Access the Company Dashboard
Navigate to your Partner Dashboard and ensure that **Test Mode** is enabled. Then, click on a company to access the Company Dashboard as an Admin.
### Add a Work Location
Click on the **Work Locations** page, then click **Add New Location**.
On the Work Location page fill the form that appears with a taxable address, then click **Create**.
***
## Recap
* A Work Location is required to onboard employees
* Work Locations can be created using the [Resolve Taxable Location](/reference/taxable-locations/resolve-taxable-location) and [Create Work Location](/reference/work-locations/create-work-location) endpoints
* Work Locations can also be created from the Company Dashboard
# Worker Dashboards
Source: https://docs.zeal.com/docs/worker-dashboards-guides
Once our workers are onboarded and able to be paid, they need a place to view paystubs and personal information. Worker dashboards are a key piece of the payroll system which provide a great experience for our workers.
## In this guide
* How to build an employee dashboard.
* How to build a contractor dashboard.
## Employee Dashboard
Employees use an employee dashboard to view paystubs, edit personal information, and access end-of-year W-2 forms.
Learn more about the [Employee Dashboard](/docs/employee-dashboards-guide).
## Contractor Dashboard
Contractors use an employee dashboard to view payments, edit personal information, and access end-of-year 1099 forms.
Learn more about the [Contractor Dashboard](/docs/contractor-dashboard-guide).
# Worker Onboarding
Source: https://docs.zeal.com/docs/worker-onboarding-guides
Workers are at the core of every payroll solution - they're who we pay after all. Before we can pay a worker, their information needs to be submitted through onboarding.
## In this section
* How to add a Work Location.
* How to onboard a W-2 Employee.
* How to onboard a 1099 Contractor.
## Work Locations
Work Locations show where an employer has employees working. It's important to track where employees complete work so that we can tax them properly.
Learn more about [Work Locations](/docs/work-locations-guide).
## Employee Onboarding
To onboard a W-2 employee, we need to collect basic information, bank details, and tax parameters. Employee onboarding is an important component of your payroll product and can be built using various methods.
Learn more about [Employee Onboarding](/docs/employee-onboarding-guide).
## Contractor Onboarding
While onboarding a 1099 Contractor is simpler than onboarding an employee, we still need to collect some basic information. Contractor onboarding is an important component if you plan on supporting contractors.
Learn more about [Contractor Onboarding](/docs/contractor-onboarding-guide)
# Bank Account Object
Source: https://docs.zeal.com/reference/bank-accounts/bank-account-object
The Zeal object representing a worker bank account.
Represents a valid checking or savings bank account for a worker (employee or contractor). US accounts use `routing_number` + `account_number`. Canadian accounts use `transit_number` + `institution_number` + `account_number` (do not send `routing_number` with Canadian fields). **NOTE: Canadian bank accounts are only applicable for Canadian Payroll (Early Access)**
| attribute | type | description |
| -------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `bankAccountID` | string | Zeal Bank Account ID |
| `companyID` | string | Zeal Company ID |
| `id` | string | Zeal Employee ID or Contractor ID |
| `institution_name` | string | Institution name for the bank account (bank name) |
| `account_number` | string | Account number of the bank account |
| `routing_number` | string | Routing number of the bank account (US). Null for Canadian bank accounts |
| `transit_number` | string | Canadian transit number (exactly 5 digits). Null for US bank accounts **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| `institution_number` | string | Canadian institution number (exactly 3 digits). Null for US bank accounts **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| `type` | string | Account type - `checking` or `savings` |
| `nickname` | string | Nickname of the bank account |
```json US bank account theme={null}
{
"bankAccountID": "0987675234",
"companyID": "0987654321",
"id": "1234567890",
"institution_name": "PNC",
"account_number": "091736576493",
"routing_number": "092784765833",
"transit_number": null,
"institution_number": null,
"type": "checking",
"nickname": "Main spending account"
}
```
```json Canadian bank account theme={null}
{
"bankAccountID": "0987675234",
"companyID": "0987654321",
"id": "1234567890",
"institution_name": "RBC",
"account_number": "1234567",
"routing_number": null,
"transit_number": "12345",
"institution_number": "001",
"type": "checking",
"nickname": "Main spending account"
}
```
# Create Bank Account
Source: https://docs.zeal.com/reference/bank-accounts/create-bank-account
openapi/zeal-api.json post /bankaccount
Create a bank account object for a worker (employee or contractor) in Zeal's system, used to pay the worker through direct deposit.
> Please ensure that you are providing validated bank account information.
# Get Bank Account by ID
Source: https://docs.zeal.com/reference/bank-accounts/get-bank-account-by-id
openapi/zeal-api.json get /bankaccount
Retrieve a single bank account object by its Zeal bank account ID.
Returns the single [bank account object](/reference/bank-accounts/bank-account-object) matching the given `bankAccountID`. To list every bank account belonging to a worker instead, use [Get Bank Accounts by Worker ID](/reference/bank-accounts/get-bank-accounts-by-worker-id).
# Get Bank Accounts by Worker ID
Source: https://docs.zeal.com/reference/bank-accounts/get-bank-accounts-by-worker-id
openapi/zeal-api.json get /bankaccount/
Retrieve all bank account objects belonging to a worker (employee or contractor) by their Zeal ID.
Returns a list of every [bank account object](/reference/bank-accounts/bank-account-object) belonging to the worker (employee or contractor) with the given `id`. To fetch a single account by its own ID instead, use [Get Bank Account by ID](/reference/bank-accounts/get-bank-account-by-id).
This is the same underlying `GET /bankaccount` endpoint as [Get Bank Account by ID](/reference/bank-accounts/get-bank-account-by-id) - the two pages document its two request/response shapes: pass a worker `id` to get a list, or a `bankAccountID` to get a single object.
# Update Bank Account
Source: https://docs.zeal.com/reference/bank-accounts/update-bank-account
openapi/zeal-api.json patch /bankaccount
Updates a bank account belonging to the specified worker in Zeal.
# Create Company
Source: https://docs.zeal.com/reference/companies/create-company
openapi/companies.json post /companies
Create a new employer company under your Zeal partner account. Returns a companyID used in all subsequent company and payroll API calls.
This endpoint registers a new employer company under your Zeal partner account and returns a `companyID` you will use in every subsequent API call for that company. See [The Company Object](/reference/companies/the-company-object) for the full field reference.
# Get Company Information
Source: https://docs.zeal.com/reference/companies/get-company-information
openapi/companies.json get /companies
Retrieve company information for one or all employers under your Zeal partner account.
Returns the matching [Company Object](/reference/companies/the-company-object) for the given `companyID`.
# Get Company Onboarding Link
Source: https://docs.zeal.com/reference/companies/get-company-onboarding-link
openapi/companies.json get /companies/onboard
Retrieve a link to Zeal's web-based company onboarding flow.
This endpoint returns a link to Zeal's web-based company onboarding flow, which collects required information such as legal business name, FEIN, legal business address, and bank account information.
This link expires exactly 7 days after generation.
# The Company Object
Source: https://docs.zeal.com/reference/companies/the-company-object
The Company object represents an employer in Zeal, including business details, owner information, and onboarding status.
The Company object represents an employer in Zeal.
| Attribute | Type | Description |
| -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `companyID` | string | CompanyID of company |
| `status` | string | Tracks the company onboarding lifecycle. Holds one of the following values: `initial_onboarding` (still onboarding), `payroll_access_needed` (Zeal still needs access to this company's previous payroll provider to migrate records), `migration_pending` (Zeal is still migrating records from the previous payroll provider), `payment_permission_pending` (data migration is done but not ready to run payroll, usually pending banking partner information), `live` (ready to process payroll), `offboarded` (company has been offboarded) |
| `first_name` | string | First name of primary business owner |
| `last_name` | string | Last name of primary business owner |
| `email` | string | Email address of primary business owner |
| `business_name` | string | Business name |
| `business_ein` | string | FEIN of company |
| `business_address` | string | Business address of company (Line 1 and Line 2 combined) |
| `business_city` | string | Business address of company (city) |
| `business_state` | string | Business address of the company (state abbreviation) |
| `business_zip` | string | Business address of company (5-digit zip code) |
| `business_phone` | string | Primary phone number of the company |
| `mail_address` | string | Mailing address of the company |
| `mail_city` | string | Mailing city of the company |
| `mail_state` | string | Mailing state of the company |
| `mail_zip` | string | Mailing ZIP code of the company |
| `skip_migration` | boolean | Defaults to `false`. If `true`, Zeal skips migrating payroll information from the company's old payroll provider. Confirm with the company that migration is not necessary - failure to migrate old records may impact tax reporting and filing. |
| `account_number` | string | Account number of the company's bank account |
| `routing_number` | string | Routing number of the company's bank account |
| `requirements` | array | List of required information for this company account (e.g. information that needs to be collected before running payments, payroll registration information, etc.). See [The Requirement Object](/reference/companies/the-requirement-object). |
| `onboarding_url` | string | URL of the company's onboarding flow if the company is still onboarding (`status` is `initial_onboarding`). Otherwise `null`. |
| `is_sandbox` | boolean | Determines the test status of the company. `false` when the company was created in Production mode or using the Production API key. |
| `ssn` | string | Social Security Number of the primary business owner |
| `ownership_percentage` | integer | The ownership percentage held by the primary business owner |
| `dob` | string | Date of birth of the primary business owner, in `MM/DD/YYYY` format |
| `legal_structure` | enum | One of: `ccorp`, `corp`, `estate`, `foreign_entity`, `llc`, `llp`, `lp`, `nonprofit`, `partnership`, `scheme`, `scorp`, `soleprop`, `trust` |
| `job_title` | string | The job title of the primary business owner |
| `address` | string | Address of the primary business owner |
| `address_line2` | string | Address line 2 of the primary business owner |
| `city` | string | City of the primary business owner |
| `state` | string | State of the primary business owner |
| `zip` | string | Zip code of the primary business owner |
| `company_type` | enum | `all` for a company that supports both 1099 contractors and W-2 employees. `contractor_only` for a company that solely supports 1099 contractors. |
| `payroll_schedule` | enum | The default payroll schedule the company follows. One of: `daily`, `weekly`, `biweekly`, `semimonthly`, `monthly` |
| `payroll_firstDate` | date | The ISO-8601 date of the first regular payroll |
| `payroll_firstPayPeriodID` | string | Reporting period ID of the first regular payroll |
```json theme={null}
{
"companyID": "1234567890",
"status": "migration_pending",
"first_name": "Erlich",
"last_name": "Bachman",
"email": "founder@aviato.com",
"business_name": "Aviato",
"business_ein": "083746568",
"business_address": "1 Market St.",
"business_city": "San Francisco",
"business_state": "CA",
"business_zip": "94105",
"mail_address": "1 Market St.",
"mail_city": "San Francisco",
"mail_state": "CA",
"mail_zip": "94105",
"skip_migration": false,
"business_phone": "4046762121",
"account_number": "123456789",
"routing_number": "0987654321",
"requirements": [],
"onboarding_url": null,
"is_sandbox": true,
"ssn": "22-333-4444",
"ownership_percentage": 25,
"dob": "01/01/1990",
"legal_structure": "ccorp",
"job_title": "CEO",
"address": "1 Ferry Building",
"city": "San francisco",
"state": "CA",
"zip": "94105",
"company_type": "all",
"payroll_firstDate": "2024-08-30",
"payroll_schedule": "weekly",
"payroll_firstPayPeriodID": "6580ce4a3808d60023b4e412"
}
```
# The Requirement Object
Source: https://docs.zeal.com/reference/companies/the-requirement-object
The Requirement object lists information Zeal needs from an employer to complete tax setup, filing, or payment for a jurisdiction.
| Attribute | Type | Description |
| ------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `companyID` | string | ID of company |
| `type` | string | Type of requirement. Holds one of the following values: `sit_payment` / `sui_payment` - the SIT + SUI payment portions of the tax setup page list the information and steps needed from employers to make timely payment for that tax; requirements vary by jurisdiction, employer category, and tax type, and often include a state tax ID number, deposit frequency, tax rate, and legal documents granting Zeal authority to make payments on the employer's behalf. `sit_filing` / `sui_filing` - the filings portion of the tax setup page lists the information Zeal needs to promptly file employment tax returns with relevant tax agencies, commonly including portal access instructions and filing frequency. `local_misc` - the local and miscellaneous section contains the list of items Zeal requires to calculate, withhold, and remit local-level taxes, such as rates, deposit frequencies, exemption status, and tax ID numbers. |
| `state` | string | The corresponding state related to this requirement, represented by the two-letter state abbreviation (if applicable) |
| `name` | string | Name, or title, of the requirement |
| `description` | string | Description of the requirement |
```json theme={null}
{
"companyID": "24b5b29f07924840b119c34c1358940c",
"description": "Missing SUI Filings Information in Georgia",
"name": "SUI Filings",
"state": "GA",
"type": "sui_filing"
}
```
# Update Company Information
Source: https://docs.zeal.com/reference/companies/update-company-info
openapi/companies.json patch /companies
Update an existing company's business details, owner information, or payroll schedule.
Patches company information and returns the updated [Company Object](/reference/companies/the-company-object). Only the company object fields documented in this API reference can be patched via this endpoint.
# Sign Company Authorization Documents
Source: https://docs.zeal.com/reference/company-onboarding/create-company-authorization-documents
openapi/zeal-api.json post /companies/authorization_documents
Sign authorization documents required to onboard a company: Tax Information Terms, Reporting Agent Terms, Direct Deposit, and Terms and Conditions Forms.
# Create Company Bank Account
Source: https://docs.zeal.com/reference/company-onboarding/create-company-bank-account
openapi/zeal-api.json post /companies/bank
Add bank account information for a company, used for company debits, worker payouts, and micro-deposit verification during onboarding.
# Get Company Authorization Documents
Source: https://docs.zeal.com/reference/company-onboarding/get-company-authorization-documents
openapi/zeal-api.json get /companies/authorization_documents
View documents that require authorization in order to onboard a company: Tax Information Terms, Reporting Agent Terms, Direct Deposit, and Terms and Conditions Forms.
# Set Company Onboarded Status to True
Source: https://docs.zeal.com/reference/company-onboarding/set-company-status-to-onboarded
openapi/zeal-api.json post /companies/onboardCompany
Once microdeposits have been confirmed and authorization documents signed, complete onboarding for the specified company.
> Note: The company is initially set to a `payment_permission_pending` state when onboarded. Please refer to the [Company Object](/reference/companies/the-company-object) for more information on company statuses.
# Trigger Micro-Deposits
Source: https://docs.zeal.com/reference/company-onboarding/trigger-microdeposits
openapi/zeal-api.json post /companies/microdeposits/trigger
Triggers micro-deposit amounts to a company bank account for verification, usually appearing in 2-3 business days.
# Verify Microdeposit Values
Source: https://docs.zeal.com/reference/company-onboarding/verify-microdeposit-values
openapi/zeal-api.json post /companies/microdeposits/verify
Submit microdeposit amounts to verify company bank accounts.
> Note: Microdeposit values are always decimal values - passing non-decimal values in this request will cause this API to fail.
# Create Contractor Deduction Template
Source: https://docs.zeal.com/reference/contractor-deduction-templates/create-contractor-deduction-template
openapi/zeal-api.json post /contractor-deduction-templates
Create a deduction template for a contractor, such as a miscellaneous deduction.
# Delete Contractor Deduction Template
Source: https://docs.zeal.com/reference/contractor-deduction-templates/delete-contractor-deduction-template
openapi/zeal-api.json delete /contractor-deduction-templates
Delete a contractor deduction template by deductionTemplateID.
# Get Contractor Deduction Templates
Source: https://docs.zeal.com/reference/contractor-deduction-templates/get-contractor-deduction-templates
openapi/zeal-api.json get /contractor-deduction-templates
Retrieve contractor deduction templates for a company, optionally filtered by contractorID or deduction_type.
# Update Contractor Deduction Template
Source: https://docs.zeal.com/reference/contractor-deduction-templates/update-contractor-deduction-template
openapi/zeal-api.json patch /contractor-deduction-templates
Update fields on an existing contractor deduction template by deductionTemplateID.
# Create Contractor ID Upload Link
Source: https://docs.zeal.com/reference/contractor-onboarding/create-contractor-id-verification-link
openapi/zeal-api.json post /contractors/id_upload_link
Creates a shareable link for contractors to submit their ID verification information when they receive an id_verification_required status.
# Create Instant Pay Contractor Enrollment Link
Source: https://docs.zeal.com/reference/contractor-onboarding/create-instant-pay-enrollment-link
openapi/zeal-api.json post /contractors/instant-pay
Create an enrollment link for a contractor to enroll in Instant Pay.
# Create Paycard Enrollment Link (Early Access)
Source: https://docs.zeal.com/reference/contractor-onboarding/create-paycard-enrollment-link
openapi/zeal-api.json post /contractors/paycard
Generate a link for a contractor to complete Paycard Enrollment.
This endpoint provides a link for a contractor to complete Paycard Enrollment.
# Generate Contractor Onboarding Link
Source: https://docs.zeal.com/reference/contractor-onboarding/generate-contractor-onboarding-link
openapi/zeal-api.json post /contractors/onboard
Generate an expirable link to Zeal's hosted contractor onboarding flow.
Generate an expirable link to Zeal's contractor onboarding. Zeal's onboarding collects:
* Profile information (e.g. SSN, DOB, Address)
* Contractor account username and password (optional)
* Contractor Survey attributes (optional). **NOTE: Only applicable for Custom Attributes (Early Access)**
* ID collection (optional - Zeal collects Driver's License + Social Security Card OR Passport)
NOTE - If passing the onboarding link in a `src` of an iframe, the `allow="camera"` flag must be passed in order for the iframe to prompt or access a user's camera.
* Paperwork (W9 form)
* Bank Account Information (optional)
* Paycard enrollment information for the contractor (optional). **NOTE: Only applicable for Paycards (Early Access)**
* Instant Pay enrollment information for the contractor (optional). **NOTE: Only applicable for Instant Pay (Early Access)**
You can choose whether you want to turn on or off these sections of Zeal onboarding by using this endpoint. This onboarding flow was custom-made to take less than 3 minutes to complete. After onboarding is completed, the contractor can start getting paid!
## Returns
| attribute | type | description |
| --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | Response status |
| data | string | Web onboarding link for this contractor |
| errors | array | Contains a list of error objects which consists of: `message` (error message) and `code` (error code, see [Error codes](https://docs.zeal.com/reference/introduction/error-codes)) |
# Send Contractor Onboarding Link
Source: https://docs.zeal.com/reference/contractor-onboarding/send-contractor-onboarding-link
openapi/zeal-api.json post /sendContractorLink
Sends a contractor onboarding link to the specified contractor's email in Zeal.
# Set Onboarded Status to True
Source: https://docs.zeal.com/reference/contractor-onboarding/set-onboarded-status-to-true
openapi/zeal-api.json post /contractors/setOnboardedStatusToTrue
Set a contractor as onboarded once all legally required information has been provided.
Set onboarded status to `true` if the contractor has all the legally required information. If the contractor does not have the aforementioned properties, Zeal will return an array of errors stating which properties are missing.
# Contractor Payment Object
Source: https://docs.zeal.com/reference/contractor-payments/contractor-payment-object
The Contractor Payment Object represents a payment made out to a Contractor Object.
The Contractor Payment Object represents a payment made out to a [Contractor Object](/reference/contractors/contractor-object).
| attribute | type | description |
| :--------------------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contractorPaymentID` | string | Zeal Contractor Payment ID |
| `contractorID` | string | Zeal Contractor ID |
| `companyID` | string | Zeal Company ID |
| `status` | string | Holds one of the following values: `pending` `pre-processed` `processed` |
| `paymentGroupID` | string (optional) | ID of the contractor payment group this payment belongs to. Zeal assigns this when the payment is pre-processed (or processed via Instant Pay) and batched into a payment group for company debit. Omitted for `pending` payments that have not been grouped yet. |
| `approval_required` | boolean (optional) | Whether manual approval is required for this payment or not. By default, Zeal automatically processes the payment two business days before the pay date. However, if approval is required and the payment is not approved by time of processing, Zeal will NOT process the payment. |
| `approved` | boolean (optional) | Whether this payment has been manually approved or not (only relevant if `approval_required` is true) |
| `pay_date` | date | Date of Pay Date for this contractor payment, in the ISO-8601 format in UTC. Zeal will pay this contractor on this date. Example `2019-10-01` |
| `amount` | number | Amount to be paid to the contractor |
| `disbursement` | object | This object includes information regarding how the pay is disbursed to the contractor.
Zeal supports 6 disbursement methods: Direct Deposit, Download Check, Physical Check, Prepaid, Paycards (Early Access), and Instant Pay (Early Access).
Show disbursement fields:
**method** (type: string, default: `direct_deposit`)
**history** (type: array) Provides an array of transaction updates
**status** (type: string) Provides an up-to-date status of the payment. The `status` will hold one of the following values:
`pending`: Status of all checks until net pay has been started
`settled` - Funds have successfully settled in employee's account
`void` - When an Employer pays out the wrong person or the wrong amount and wants to void the check
`returned` - Net pay did not successfully get disbursed
`refunded` - Status of checks that failed but then the employer wants to pay out in-house (only applicable to direct deposit payments)
`canceled` - The check got canceled due to going to an inactive user or having a transaction going to a watchlist match (only applicable to direct deposit payments) |
| `type` | string | Type of payment. Only `regular` payments are reported on a contractor's Form 1099-NEC. Holds one of the following values - `regular`, `reimbursement` |
| `speed` | string | The ACH speed of the check, accepts `two_day`, `one_day` or `one_day_no_reserve`, `zero_day`, `instant` as values. (Early Access) |
| `triggered` | boolean | Whether a disbursement has been triggered. Only applicable if disbursement method is `paycard` or `instant_pay` |
| `triggered_at` | datetime | Timestamp of when the disbursement was triggered, in the ISO-8601 format in UTC. |
| `customerAccountID` (Early Access) | string | Can be used to attach a customer account to a contractor payment |
| `metadata` | object | Custom object you can attach to the contractor payment object. This is useful for storing additional information about the object in a custom, structured format. See [Metadata](/reference/introduction/metadata) |
| `payment_items` | array | List of payment item objects associated with this contractor payment |
| `apply_contractor_deductions` | boolean | Applies a deduction to this payment for each contractor deduction template that is effective at the time of the pay date for the contractor. **Note**: Only applicable when `payment_items` is provided |
```json EXAMPLE CONTRACTOR PAYMENT OBJECT theme={null}
{
"contractorPaymentID": "4f3c8e7f0d4c489a92df124aef6d6578",
"contractorID": "9b1320c5d4d34761b57b0ac09b24037a",
"companyID": "df2a785b82cb4f46b765a8580e7e9c2f",
"status": "processed",
"paymentGroupID": "8808c9c05afd407393d25b8de7f55a23",
"approval_required": false,
"approved": false,
"pay_date": "2024-10-01",
"amount": "100",
"disbursement": {
"method": "direct_deposit",
"history": [],
"status": "settled"
},
"type": "regular",
"triggered": true,
"triggered_at": "2025-03-04T23:18:09Z",
"customerAccountID": null,
"metadata": {}
}
```
## Types of Disbursement Methods
**Direct Deposit**: The most convenient disbursement type is to do a direct deposit into the employee's bank account, from the employers. In this case, Zeal will include the employee net pay in the Company Debit number of the employer check (i.e. net pay is debited from the employer's bank account.
The net pay is deposited into the employee bank account at check date.
**Download check**: Checks are useful for certain employees who prefer to be paid in checks instead of direct deposits. We do not include net pay from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is "download check").
Net pay is only taken out of the employers bank account when the employee cashes the check. The account / routing number is that of the employers.
The link for downloading the check becomes available by check date on the employee dashboard.
**Physical check**: For employees where net pay speed delivery is not an issue, and who prefer to be paid with a physical, mailed check instead of the download check or direct deposit methods. We do not include the net pay amount from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is "phsyical check").
Net pay is only taken out of the employers bank account when the employee cashes the check. The account / routing number is that of the employers.
The physical check is created on the check date, and sent to the home address listed for the employee in Zeal. Its arrival time will depend on the location of the employee.
**Prepaid**: Prepaid is used when the employer does want to use direct deposit, but instead has an alternate method of paying their employees. In that case, Zeal does not include net pay from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is prepaid). Instead the employer is shown the net pay they owe their employees after taking out the appropriate taxes.
The employer is responsible for disbursing net pay outside of Zeal.
**Paycard**: If an employee has a paycard, the `paycard` disbursement method can be used to direct funds to the existing paycard. This allows for instantaneous payout and does not depend on ACH timings and delays. **Note: This is only available for Paycards product (Early Access)**
**Instant Pay**: If an employee has an Instant Pay wallet, the `instant_pay` disbursement method can be used to direct funds to their wallet. This allows for instantaneous payout and does not depend on ACH timings and delays. **Note: This is only available for Instant Pay product (Early Access)**
# Create Contractor Payment
Source: https://docs.zeal.com/reference/contractor-payments/create-contractor-payment
openapi/zeal-api.json post /contractorPayment
Create a contractor payment in Zeal; the payment is processed the day before the pay_date.
Create a contractor payment in Zeal. Zeal will process the payment for the contractor the day before the `pay_date`.
Multiple contractor payments may be submitted for the same contractor and the same `pay_date`.
## Returns
Returns boolean indicating success status and contractor payment object if successful.
| attribute | type | description |
| --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | Response status |
| data | object | Contractor Payment object |
| errors | array | If `success` is false, errors contains a list of error objects: `message` (string, error message), `status` (number, HTTP response code), `code` (number, error code - see [Error codes](https://docs.zeal.com/reference/introduction/error-codes)) |
# Delete Contractor Payment
Source: https://docs.zeal.com/reference/contractor-payments/delete-contractor-payment
openapi/zeal-api.json delete /contractorPayment
Delete a pending contractor payment by contractorPaymentID in Zeal.
# Get Contractor Payments
Source: https://docs.zeal.com/reference/contractor-payments/get-contractor-payments
openapi/zeal-api.json get /contractorPayment
Retrieve a contractor payment by contractorPaymentID, or list payments for a company, optionally filtered by contractorID.
This endpoint serves two usages on the same path. Pass `companyID` and `contractorPaymentID` to retrieve a single contractor payment. Omit `contractorPaymentID` to list payments for a company; you can optionally pass `contractorID` (and `status` or `paymentGroupID`) to filter that list.
When `contractorPaymentID` is present, list filters such as `contractorID` are ignored.
## Returns
Returns response status and the contractor payment (or a paginated list of contractor payments).
| attribute | type | description |
| --------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | Response status |
| data | object or array | Contractor Payment object, or an array of contractor payments when listing |
| errors | array | If `success` is false, errors contains a list of error objects: `message` (string, error message), `status` (number, HTTP response code), `code` (number, error code - see [Error codes](https://docs.zeal.com/reference/introduction/error-codes)) |
# Trigger Disbursement
Source: https://docs.zeal.com/reference/contractor-payments/trigger-disbursement
openapi/zeal-api.json post /contractorPayment/trigger
Trigger early disbursement of a pending contractor payment before the standard cutoff time.
# Update Contractor Payment
Source: https://docs.zeal.com/reference/contractor-payments/update-contractor-payment
openapi/zeal-api.json patch /contractorPayment
Update fields on an existing, pending contractor payment in Zeal.
# Contractor Object
Source: https://docs.zeal.com/reference/contractors/contractor-object
The Contractor Object represents a 1099 contractor for a given company.
The Contractor Object represents a 1099 contractor for a given company.
| attribute | type | description |
| ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contractorID` | string | Zeal Contractor ID |
| `companyID` | string | Zeal Company ID |
| `onboarded` | boolean | Whether the contractor has been onboarded onto Zeal or not |
| `type` | enum | One of: `individual_sole_proprietor`, `c_corporation`, `s_corporation`, `partnership`, `trust_estate`, `llc`, `other` |
| `llc_tax_classification` | enum | One of: `c_corporation` (default), `s_corporation`, `partnership` (only applicable if `type` is `llc`) |
| `tin_type` | enum | One of: `ssn`, `ein` (if `ein` is passed, the `ein` field is required; only applicable if `type` is `individual_sole_proprietor`) |
| `first_name` | string | First name of the contractor |
| `middle_name` | string | Middle name of the contractor |
| `last_name` | string | Last name of the contractor |
| `email` | string | Email of contractor |
| `dob` | date | Date of birth of contractor |
| `phone_number` | string | Phone number of contractor |
| `ssn` | string | Social security number of the contractor |
| `ein` | string | EIN of the contractor (applicable for all `type` options, except if `type` is `individual_sole_proprietor` and `tin_type` is `ein`) |
| `business_name` | string | Business name of the contractor (applicable for all `type` options, except `individual_sole_proprietor`) |
| `address` | string | Residential street address of the contractor |
| `address_line2` | string | Additional address line if needed |
| `city` | string | Residential city of contractor |
| `state` | string | Residential state of the contractor |
| `zip` | string | Residential zip code of the contractor |
| `employment_status` | string | Employment status of the contractor. Default value is `live`; other accepted values are `leave` and `terminated`. |
| `external_id` | string | External ID for a contractor that comes from an employer's HR or other internal systems |
| `paycard_requested` | boolean | Set to `true` if the contractor has completed paycard enrollment. The paycard may not be successfully provisioned yet. Only applicable for Paycards (Early Access). |
| `paycard_enabled` | boolean | Set to `true` if the contractor has completed paycard enrollment and the paycard has successfully been provisioned. Only applicable for Paycards (Early Access). |
| `kyc_status` | enum | One of: `null`, `approved`, `denied` |
| `ssn_verification_status` | enum | One of: `null`, `approved`, `declined` |
| `instant_pay_enabled` | boolean | Set to `true` if the contractor has completed instant pay enrollment. Only applicable for Instant Pay (Early Access). |
```json theme={null}
{
"contractorID": "c9f1e2a47d3b4f8a9c2e1a6b8d4f3e21",
"companyID": "a7e3c91f4b2d8f5e9c6a1d0b4e8f2c73",
"onboarded": true,
"type": "c_corporation",
"tin_type": null,
"first_name": "erlich",
"middle_name": null,
"last_name": "bachman",
"email": "erlich@aviato.com",
"dob": "1998-05-05",
"phone_number": "4154645367",
"ein": "12-3456789",
"business_name": "Monster Cookies",
"address": "320 Pancake Hollow Road",
"address_line2": null,
"city": "Highland",
"state": "NY",
"zip": "12528",
"employment_status": "live",
"external_id": "123",
"paycard_requested": false,
"paycard_enabled": false,
"kyc_status": "approved",
"ssn_verification_status": "approved",
"instant_pay_enabled": true
}
```
# Create Contractor
Source: https://docs.zeal.com/reference/contractors/create-contractor
openapi/zeal-api.json post /contractors
Create one or more 1099 contractors under a company in Zeal.
See the [Contractor Object](/reference/contractors/contractor-object) for the full field reference.
# Get Contractor Information
Source: https://docs.zeal.com/reference/contractors/get-contractor-information
openapi/zeal-api.json get /contractors
Retrieve key information about a single 1099 contractor by contractorID.
This request uses the `contractorID` attribute to return key information about the contractor, contained within the [Contractor Object](/reference/contractors/contractor-object). This is the same underlying route as [Get Contractors](/reference/contractors/get-contractors), which lists/filters instead of looking up a single contractor - the API doesn't distinguish these with separate routes, so each page documents the query parameters for its own intended usage.
This applies to 1099 contractors. For W-2 employees, use the [Get Employee Information](/reference/employees/get-employee-information) request instead.
## Returns
Returns response status and the [Contractor Object](/reference/contractors/contractor-object) for the requested contractor.
| attribute | type | description |
| --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | Response status |
| data | object | Contractor Object for the requested contractor |
| errors | array | Contains a list of error objects which consists of: `message` (error message) and `code` (error code, see [Error codes](https://docs.zeal.com/reference/introduction/error-codes)) |
# Get Contractors
Source: https://docs.zeal.com/reference/contractors/get-contractors
openapi/zeal-api.json get /contractors
Retrieve information on contractors for a company, with optional filters.
This uses the same underlying endpoint as [Get Contractor Information](/reference/contractors/get-contractor-information), which looks up a single contractor by `contractorID` instead of listing/filtering - the API does not distinguish these with separate routes, so the query parameters accepted differ by intended usage. This page's usage: pass `companyID` and any of the optional filters below (omit `contractorID`) to get a filtered list of contractors.
# Update Contractor Information
Source: https://docs.zeal.com/reference/contractors/update-contractor-information
openapi/zeal-api.json patch /contractors
Update fields on an existing 1099 contractor's record in Zeal.
# Upload Contractor Government ID
Source: https://docs.zeal.com/reference/contractors/upload-contractor-government-id
openapi/zeal-api.json post /contractors/id
Upload a base64-encoded government ID (driver's license, social security card, or passport) for a contractor.
# Custom Attribute Object
Source: https://docs.zeal.com/reference/custom-attributes/custom-attribute-object
The Custom Attribute object represents an attribute that can be set on an employee or contractor.
The Custom Attribute object represents an attribute that can be set on an employee or contractor.
| attribute | type | description |
| :------------- | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `attributeID` | string | Unique identifier for the attribute |
| `companyID` | string | Unique identifier for Zeal company |
| `type` | string | Type of paperwork form. Holds one of the following values: `boolean`, `options`, `string` |
| `description` | string | Description of the paperwork form |
| `options` | array | Array of options, represented as objects. Each option object includes `name` and `value`. **Only applicable if `type` is `options`** |
| `constraints` | object | The constraints object includes `minLength` (minimum length of string), `maxLength` (minimum length of string) and `pattern` (regex constraint, if applicable). **Only applicable if `type` is `string`** |
| `name` | string | Human-friendly name of the attribute (used and viewed by admins) |
| `label` | string | The label of the field. This will show as the label to workers |
| `value` | object | Value of the attribute |
| `defaultValue` | string | Default value |
## Example Custom Attribute Object
```json Boolean Example theme={null}
{
"companyID": "dcb3bd9403ad41c98bbc2b4d54d88a44",
"attributeID": "694eb6b0-6441-4150-88a2-5bd0fae84171",
"type": "boolean",
"description": "",
"name": "Acknowledge",
"label": "Agree",
"value": "false",
"defaultValue": false
}
```
```json String Example theme={null}
{
"companyID": "6cb3b69463ad41c986bc2b6d64d68a46",
"attributeID": "c3267432fa464fd8b9b79b0d53552562",
"type": "string",
"name": "test text",
"label": "test text",
"description": "",
"constraints": {
"minLength": 5,
"maxLength": 10,
"pattern": null
},
"value": " ",
"defaultValue": " "
}
```
```json Options Example theme={null}
{
"companyID": "6cb3b69463ad41c986bc2b6d64d68a46",
"attributeID": "9ecd856e8b3c4337a6330dcadf2a8fc4",
"type": "options",
"name": "T-shirt size",
"label": "T-shirt size",
"description": "",
"options": [
{
"value": "S",
"name": "S"
},
{
"value": "M",
"name": "M"
},
{
"value": "L",
"name": "L"
},
{
"value": "XL",
"name": "XL"
}
],
"value": "XS",
"defaultValue": " "
}
```
# Get Attributes
Source: https://docs.zeal.com/reference/custom-attributes/get-attributes
openapi/zeal-api.json get /attributes
Retrieve the custom attributes set on an employee or contractor.
# Set Attribute Value
Source: https://docs.zeal.com/reference/custom-attributes/set-attribute-value
openapi/zeal-api.json patch /attributes
Set the value of custom attributes on an employee or contractor.
# Create Customer Account
Source: https://docs.zeal.com/reference/customer-accounts/create-customer-account
openapi/zeal-api.json post /customer-accounts
Create a new customer account under a company.
# Create Funding Source
Source: https://docs.zeal.com/reference/customer-accounts/create-funding-source
openapi/zeal-api.json post /customer-accounts/{id}/funding-sources
Create a bank account funding source for a customer account using account and routing numbers.
# Customer Account Object
Source: https://docs.zeal.com/reference/customer-accounts/customer-account-object
The Customer Account Object represents a client under a Company that workers, checks, and shifts can be attributed to.
The Customer Account Object represents a client under a Company that workers, checks, and shifts can be attributed to.
| attribute | type | description |
| --------------------- | ------ | ---------------------------------------------------------------------------------------------------------------- |
| `customer_account_id` | string | Unique identifier representing this customer account |
| `company_id` | string | Company ID that this customer account is under |
| `partner_id` | string | Partner ID associated with the Company and customer account |
| `code` | string | Custom code to be associated with the customer account |
| `business_name` | string | Business name of customer account |
| `ein` | string | EIN of the customer account |
| `legal_structure` | string | Federal tax classification of the customer account entity |
| `phone` | string | Phone number of the customer account |
| `email` | string | Business email of the customer account |
| `business_address` | string | Street address of the customer account |
| `business_city` | string | City |
| `business_state` | string | US State or Territory (2-letter abbreviation) |
| `business_zip` | string | ZIP code (5 digits) |
| `business_owner` | object | Object containing business owner (UBO) information |
| `status` | string | Onboarding status of customer account (`initial_onboarding`, `payment_permission_pending`, `live`, `offboarded`) |
| `funding_source` | object | Object containing associated Funding Source data |
```json theme={null}
{
"customer_account_id": "23b9ada702984edeb1496c1cb95abc8c",
"company_id": "dcb3bd9403ad41c98bbc2b4d54d88a44",
"partner_id": "c133eed2c9b8419ba2f22dc059bd445a",
"code": "customer-code-2",
"business_name": "Taco Bell",
"ein": "777777777",
"legal_structure": "llc",
"phone": "1234567890",
"email": "accounting@tacobell.com",
"business_address": "1 Ferry Building",
"business_city": "San Francisco",
"business_state": "CA",
"business_zip": "94103",
"business_owner": {
"first_name": "Erlich",
"last_name": "Bachman",
"email": "erlich@aviato.com",
"ssn": "345237890",
"dob": "1990-01-01",
"title": "CEO",
"ownership_percentage": 47,
"owner_type": "authorized_signer",
"address": "1600 Pennsylvania Ave NW",
"city": "Washington",
"state": "DC",
"zip": "20500"
},
"status": "live",
"funding_source": {
"account_number": "849201923",
"account_type": "checking",
"routing_number": "314074269"
}
}
```
# Generate Customer Account Onboarding Link
Source: https://docs.zeal.com/reference/customer-accounts/generate-customer-account-onboarding-link
openapi/zeal-api.json post /customer-accounts/onboard
Generate an onboarding link for a customer account.
# Get All Customer Accounts
Source: https://docs.zeal.com/reference/customer-accounts/get-all-customer-accounts
openapi/zeal-api.json get /customer-accounts
Fetch a list of Customer Accounts associated with the specified Company ID.
# Get Customer Account
Source: https://docs.zeal.com/reference/customer-accounts/get-customer-account
openapi/zeal-api.json get /customer-accounts/{customerAccountID}
Fetch a specified Customer Account object using the passed Customer Account ID.
# Set Customer Account Onboarded To true
Source: https://docs.zeal.com/reference/customer-accounts/set-customer-account-onboarded-to-true
openapi/zeal-api.json post /customer-accounts/{customerAccountID}/setOnboardedStatusToTrue
Manually set a customer account's onboarded status to true.
# Trigger Microdeposits
Source: https://docs.zeal.com/reference/customer-accounts/trigger-ca-microdeposits
openapi/zeal-api.json post /customer-accounts/{customerAccountID}/trigger-micro-deposits
Trigger microdeposits for the Customer Account funding account for verification.
# Update Customer Account
Source: https://docs.zeal.com/reference/customer-accounts/update-customer-account
openapi/zeal-api.json patch /customer-accounts/{id}
Update a specified Customer Account's business details, such as EIN, address, phone, or status.
# Verify Microdeposits
Source: https://docs.zeal.com/reference/customer-accounts/verify-microdeposits
openapi/zeal-api.json post /customer-accounts/{customerAccountID}/verify-micro-deposits
Submit microdeposit amounts to verify a customer account's bank account.
# Get Documents
Source: https://docs.zeal.com/reference/documents/get-documents
openapi/zeal-api.json get /documents
Access tax/payroll documents for a company, employee, and/or contractor, such as Quarterly Federal Tax Returns, W-2s, 1099s, etc.
# The Document Object
Source: https://docs.zeal.com/reference/documents/the-document-object
The Zeal object representing a company tax document.
| attribute | type | description |
| :------------ | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `companyID` | string | Zeal Company ID |
| `type` | string | Type of Document. Holds one of the following values: `W2`, `W2C`, `1099`, `1099MISC`, `940`, `941`, `941-X`, `943`, `943X`, `944`, `944X`, `945`, `945X`, `2678`, `2848`, `state_quarterly_contribution` |
| `description` | string | Description of the Document. The description should describe the purpose of the form, its date component, etc. |
| `id` | string | The id of the employee (`employeeID`) or id of the contractor (`contractorID`) |
| `link` | string | Link to the document |
| `year` | string | The year of the document |
| `quarter` | string | The quarter for which the tax document was filed |
```json EXAMPLE DOCUMENT OBJECT theme={null}
{
"companyID": "1b5n28nrideucd24",
"type": "W2",
"description": "2023 Wage and Tax Statement (Form W2)",
"id": "1234567890",
"link": "https://test-documents.s3.amazonaws.com/1b5n28nrideucd24-2229-W2-1234567890-document",
"year": "2023",
"quarter": "Q4"
}
```
# Accrual Balance History
Source: https://docs.zeal.com/reference/embedded-hr/accrual-balance-history
openapi/zeal-api.json post /accrualBalance/history
View accrual balance history for a company, filtered by policy code and employee IDs.
# Accrual Policy Object
Source: https://docs.zeal.com/reference/embedded-hr/accrual-policy-object
Reference for the Accrual Policy object representing a PTO, sick leave, or custom accrual policy assigned to company employees.
The Accrual Policy Object represents a PTO, sick leave, or custom accrual policy that can be created for a company and assigned to respective company employees.
| attribute | type | description |
| --------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| companyID | string | Zeal Company ID |
| policy\_code | string | Custom code that can be assigned for the policy |
| policy\_type | enum | Type of the accrual policy (accepts: pto, sick\_leave, or custom) |
| policy\_name | string | Custom name that can be assigned for the policy |
| policy\_effective\_date | YYYY-MM-DD | The effective start date of the policy |
| accrual\_rate\_hours | float | The rate at which employees will accrue hours |
| accrual\_period\_hours | float | The number of hours employees need to work to accrue accrual\_rate\_hours |
| immediate\_balance | float | The immediate hour balance the employee would receive |
| include\_doubletime | boolean | Include if double-time work is eligible for hour accrual |
| include\_overtime | boolean | Include if overtime work is eligible for hour accrual |
| include\_flat | boolean | Include if flat earning component is eligible for accrual |
| accrual\_waiting\_period | float | The number of hours the employees need to work before they are eligible to begin accruing time for policy |
| accrual\_cap | float | The maximum number of hours an employee can accrue within a policy year. Once this limit is reached, no additional hours will accrue until the next accrual period or rollover date. |
| rollover\_cap | float | The maximum number of unused hours an employee is allowed to carry over from one policy year to the next on the specified rollover date. |
| rollover\_date | float | Required if the user passes a value for `rollover_cap` or `accrual_cap` |
| balance\_cap | float | The maximum balance an employee is allowed to hold under this policy. Once this limit is reached, no additional hours will accrue until the balance drops below the cap. |
| accrual\_start\_after\_days | float | The number of calendar days after the employees' start date before they begin accruing time for the policy |
```bash bash theme={null}
{
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"policy_code": "001",
"policy_type": "pto",
"policy_name": "test name",
"policy_effective_date": "2023-03-01",
"accrual_rate_hours": 10,
"accrual_period_hours": 40,
"immediate_balance": 0,
"include_doubletime": true,
"include_overtime": true,
"include_flat": false,
"accrual_waiting_period": 0,
"accrual_cap": 100,
"rollover_cap": 40,
"rollover_date": "01-01",
"policy_status": "live",
"balance_cap": 100,
"accrual_start_after_days": 0
}
```
# Add/Remove Employees to Accrual Policy
Source: https://docs.zeal.com/reference/embedded-hr/add-employees-to-accrual-policy
openapi/zeal-api.json post /accrualPolicyEmployees
Add or remove employees from an existing accrual policy by company and policy code.
# Create Accrual Policy
Source: https://docs.zeal.com/reference/embedded-hr/create-accrual-policy
openapi/zeal-api.json post /accrualPolicy
Create a new PTO, sick leave, or custom accrual policy for a company.
# Create Accrual Policy Usage
Source: https://docs.zeal.com/reference/embedded-hr/create-accrual-policy-usage
openapi/zeal-api.json post /accrualPolicy/{policyCode}/usage
Apply accrual usage (or a correction) for one or more employees under a given accrual policy.
# Get Accrual Balance
Source: https://docs.zeal.com/reference/embedded-hr/get-accrual-balance
openapi/zeal-api.json get /accrualBalance
Retrieve an employee's or company's accrual policy balance, optionally filtered by policy code, employee, or policy status.
# Get Accrual Policy
Source: https://docs.zeal.com/reference/embedded-hr/get-accrual-policy
openapi/zeal-api.json get /accrualPolicy
Fetch an existing accrual policy for a company, optionally filtered by policy code or policy status.
# Get Minimum Wage Rules
Source: https://docs.zeal.com/reference/embedded-hr/get-minimum-wage-rules
openapi/zeal-api.json get /minimumWageRules
Fetch minimum wage rules for a specified work location, optionally as of a given effective date.
# Get Sick Time Compliance Rules
Source: https://docs.zeal.com/reference/embedded-hr/get-sick-time-compliance-rules
openapi/zeal-api.json get /sickTimeCompliance
Retrieve state and municipal compliance rules for earned paid sick leave by state and optional city.
# Update Accrual Balance
Source: https://docs.zeal.com/reference/embedded-hr/update-accrual-balance
openapi/zeal-api.json patch /accrualBalance
Update an accrual balance corresponding to an accrual policy for one or more employees.
# Update Accrual Policy
Source: https://docs.zeal.com/reference/embedded-hr/update-accrual-policy
openapi/zeal-api.json patch /accrualPolicy
Update the configuration of an existing accrual policy, such as its accrual rate, caps, rollover rules, or status.
# Create Deduction
Source: https://docs.zeal.com/reference/employee-checks/deductions/create-deduction
openapi/employee-checks.json post /deductions
Create a Deduction and attach it to a specific employee check based on a Deduction Template.
The deduction is scoped to a single employee check. Its required fields are determined by the `required_template_fields` in the [Deduction Template Definition](/reference/employee-checks/deductions/get-deduction-template-definitions).
# Create Deduction Template
Source: https://docs.zeal.com/reference/employee-checks/deductions/create-deduction-template
openapi/employee-checks.json post /deductionTemplate
Create a Deduction Template for a company that defines the rules for a class of deduction, such as a 401(k).
The fields you can include are determined by the schema returned from [Deduction Template Definition](/reference/employee-checks/deductions/get-deduction-template-definitions).
# Deduction Object
Source: https://docs.zeal.com/reference/employee-checks/deductions/deduction-object
Deduction Object is created using a Deduction Template and is attached to an Employee Check.
Deduction Object is created using a Deduction Template and is attached to an Employee Check.
The corresponding deduction template provides the JSON schema which lays out the fields needed to create a Deduction.
| attribute | type | description |
| :--------------------------------- | :----- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deductionID` | string | Zeal Deduction ID |
| `companyID` | string | Zeal Company ID |
| `employeeCheckID` | string | Zeal Employee Check ID |
| `deduction_type` | string | Type of deduction. You can find all deduction types [here](/reference/employee-checks/deductions/types-of-deductions) |
| `employer_contribution` | object | Show child attributes:
**value** - type: float - description: Employer contribution amount
**contribution\_type** - type: string - description: Can be either `dollars` or `percentage` |
| `employee_contribution` | object | Show child attributes:
**value** - type: float - description: Employee contribution amount
**contribution\_type** - type: string - description: Can be either `dollars` or `percentage` |
| `additional_fields` | object | Some deduction types like HSA or Garnishment have additional properties apart from employee and employer contributions. This field is used to provide information on those fields if set as overridable.
Show child attributes:
**order\_number** - type: float - description: The number given for the order
**case\_id** - type: string - description: Custom ID given for the case
**agency** - type: object - See next row for agency child attributes |
| `agency` | object | Falls within the additional\_fields object if relevant to the deduction type.
Show child attributes:
**name** - type: string - description: The name given of the Agency
**address** - type: string - description: The address of the Agency location |
| `employer_calculated_contribution` | number | This is the calculated amount that the employer contributed once the check has been moved from pending to pre-processed. The value while this check is pending will always be 0. |
| `employee_calculated_contribution` | number | This is the calculated amount that the employee contributed once the check has been moved from pending to pre-processed. The value while this check is pending will always be 0. |
| `deduction_template_name` | string | Name of deduction template, this deduction was created with |
| `deductionTemplateID` | string | ID of Deduction Template this deduction was created with |
# Deduction Template Definition Object
Source: https://docs.zeal.com/reference/employee-checks/deductions/deduction-template-definition-object
Deduction Template Definition represents a JSON schema that describes how to create a Deduction Template in JSON format.
Deduction Template Definition represents a [JSON schema](https://json-schema.org/), which is essentially a way to represent instructions to create a Deduction Template in a JSON format.
With Zeal, using a Deduction Template Definition object, you first create a Deduction Template, and then subsequently create a Deduction using the Deduction Template, which also contains a JSON schema.
The different types of Deduction Template Definition objects that Zeal returns are listed below.
## Types of Deductions
```json hsa theme={null}
{
"success": true,
"data": {
"type": "object",
"required": [
"employee_contribution",
"additional_fields"
],
"properties": {
"required_template_fields": {
"const": [
"employee_contribution"
]
},
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "hsa"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"additional_fields": {
"type": "object",
"properties": {
"hsa_type": {
"enum": [
"family",
"individual"
]
}
},
"required": [
"hsa_type"
]
}
}
}
}
```
```json 401k theme={null}
{
"success": true,
"data": {
"type": "object",
"required": [
"employee_contribution",
"custom_name"
],
"properties": {
"required_template_fields": {
"const": [
"employee_contribution"
]
},
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "401k"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"percentage_source": {
"const": "gross"
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
}
}
}
}
```
```json garnishment theme={null}
{
"success": true,
"data": {
"type": "object",
"required": [
"employee_contribution",
"additional_fields"
],
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "garnishment"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"value": {
"type": "number"
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
},
"additional_fields": {
"type": "object",
"required": [
"order_number",
"case_id",
"agency"
],
"properties": {
"required_template_fields": {
"const": [
"agency",
"case_id"
]
},
"order_number": {
"type": "object",
"properties": {
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"value": {
"type": "string"
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type"
]
},
"case_id": {
"type": "object",
"properties": {
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"value": {
"type": "string"
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type"
]
},
"agency": {
"type": "object",
"properties": {
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"address": {
"type": "string"
},
"name": {
"type": "string"
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"address",
"name"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"address",
"name"
]
}
}
],
"required": [
"override_type"
]
}
}
}
}
}
}
```
```json section_125 theme={null}
{
"type": "object",
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "section_125"
},
"employee_contribution": {
"properties": {
"contribution_type": {
"enum": [
"flat"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
}
},
"required_template_fields": {
"const": [
"value"
]
},
"required": [
"override_type",
"contribution_type"
]
},
"required_template_fields": {
"const": [
"employee_contribution"
]
}
}
}
```
```json miscellaneous theme={null}
{
"type": "object",
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "miscellaneous"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"post_tax": {
"type": "boolean"
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type"
]
},
"required_template_fields": {
"const": [
"employee_contribution"
]
}
}
}
```
```json roth_401k theme={null}
{
"success": true,
"data": {
"type": "object",
"required": [
"employee_contribution"
],
"properties": {
"required_template_fields": {
"const": [
"employee_contribution"
]
},
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "roth_401k"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"percentage_source": {
"const": "gross"
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"allOf": [
{
"if": {
"properties": {
"override_type": {
"const": "final"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
},
{
"if": {
"properties": {
"override_type": {
"const": "overridable"
}
},
"required": [
"override_type"
]
},
"then": {
"required": [
"value"
]
}
}
],
"required": [
"override_type",
"contribution_type"
]
}
}
}
}
```
```json 403(b) theme={null}
{
"type": "object",
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "403(b)"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"percentage_source": {
"enum": [
"contribution",
"paycheck"
]
},
"matching": {
"type": "boolean"
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type",
"matching"
]
},
"required_template_fields": {
"const": [
"employee_contribution"
]
}
}
}
```
```json simple_ira theme={null}
{
"type": "object",
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "simple_ira"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type"
]
},
"employer_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars"
]
},
"percentage_source": {
"enum": [
"contribution",
"paycheck"
]
},
"matching": {
"type": "boolean"
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type",
"matching"
]
},
"required_template_fields": {
"const": [
"employee_contribution"
]
}
}
}
```
```json roth_ira theme={null}
{
"type": "object",
"properties": {
"custom_name": {
"type": "string"
},
"deduction_type": {
"const": "roth_ira"
},
"employee_contribution": {
"type": "object",
"properties": {
"contribution_type": {
"enum": [
"dollars",
"percentage"
]
},
"value": {
"type": "number"
},
"override_type": {
"enum": [
"overridable",
"needs_input",
"final"
]
},
"required_template_fields": {
"const": [
"value"
]
}
},
"required": [
"override_type",
"contribution_type"
]
},
"required": [
"override_type",
"contribution_type",
"matching"
]
},
"required_template_fields": {
"const": [
"employee_contribution"
]
}
}
}
```
The following is a list of deductions (pre-tax and post-tax) that Zeal supports:
`401k` - (Pre-Tax) A 401(k) plan is a tax-qualified, defined-contribution pension account that provides for pretax retirement savings.
`hsa` - (Pre-Tax) A health savings account (HSA) is a tax-advantaged medical savings account enrolled in a high-deductible health plan. Funds accumulate and can be used to pay for qualified medical expenses without tax liabilities.
`garnishment` - (Post-Tax) A garnishment is a court-mandated withholding of an employee’s earnings from a paycheck for use toward debts. Common sources include child support, federal debt, state debt, student loans, and credit card debt. This serves as a post-tax deduction.
`miscellaneous` - (Post-Tax) A type for a generic post-tax deduction on the employee check.
`section_125` - (Pre-Tax) A benefit belonging to a Section 125 plan that allows employees to choose between different types of qualified benefits.
`roth_401k` - (Post-Tax) The Roth 401(k) is a defined-contribution pension account that requires that the income tax be paid immediately, so the employee's real net income is reduced by the amount earmarked for savings. Employers can match employee contributions to a Roth 401k, but those employer contributions must be matched in a separate traditional `401k` deduction.
`403(b)` - (Pre-Tax) A 403(b) plan (tax-sheltered annuity plan or TSA) is a retirement plan offered by public schools, non-profit organizations, and government entities It is similar to a 401(k) plan maintained by a for-profit entity. Just as with a 401(k) plan, a 403(b) plan lets employees defer some of their salary into individual accounts.
`simple_ira` - (Pre-Tax) A SIMPLE IRA plan (Savings Incentive Match Plan for Employees) allows employees and employers to contribute to traditional IRAs set up for employees by usually smaller businesses or companies.
`roth_ira` - (Post-Tax) A Individual Retirement Account to which you contribute after-tax dollars. Your contributions and earnings can grow tax-free, and you can withdraw them tax- and penalty-free after age 59½ and once the account has been open for five years
`calsavers` - (Post-tax) California’s state-mandated retirement savings program for employees who don’t have access to a workplace retirement plan. Employers with five or more employees are required to either offer a qualified retirement plan or register for CalSavers and facilitate payroll deductions. The program uses Roth IRAs, meaning contributions are made with after-tax dollars and qualified withdrawals are tax-free. Contributions are not tax-deductible for employees, and employers are not required to contribute or pay any fees.
`dependent_care_benefit` - (Pre Tax) Dependent care benefits refer to specific benefits that are provided by employers to their employees in the care of their dependents. Dependent care benefits are under a bigger umbrella of the employee benefits system administered by the Internal Revenue Service (IRS). A list of dependent care benefits can be found in the W-2 Form, box 10
`employer_sponsored_health_coverage` - (Pre Tax) The Affordable Care Act requires employers to report the cost of coverage under an employer-sponsored group health plan on an employee’s Form W-2, Wage and Tax Statement, in Box 12, using Code DD. The amount reported does not affect tax liability, as the value of the employer contribution continues to be excludable from an employee’s income and is not taxable. This reporting is for informational purposes only, to show employees the value of their health care benefits.\
Note - `employer_sponsored_health_coverage` needs both the employer and employee contributions. It's expected that the employee contributions will be set to 0 through the API
## Override Types
* `final` - Use this `override_type` when creating a Deduction Template, if you want to set the contribution field to only be set by the employer, and not let employees override it. An example of this would be setting the employer contribution on a 401k
* `overridable` - Use this `override_type` when creating a Deduction Template, if you want to set an initial value from the employer's side, the employee can change it. An example of this would be setting the hsa\_type to be individual at first, but allowing an employee to set it to family.
* `needs_input` - Use this `override_type` when creating a Deduction Template, if you want the employee to set their contribution amount. If the field is left blank by the employee, it will be set to 0. An example of this would be an employee setting their preferred contribution amount for a 401k plan.
## Contribution Types
* `dollars` - Amount is accepted as number
* `percentage` - Amount is to be accepted as a percentage of the pay, e.g. 10.21
# Deduction Template Object
Source: https://docs.zeal.com/reference/employee-checks/deductions/deduction-template-object
Deduction Template Object represents a template that can be used to create Deductions.
Deduction Template Object represents a template that can be used to create Deductions. A template is used in order to allow employers to have flexibility in creating different forms of deductions. For example, with Deduction Templates, an employer can create one template where contributions are set out in dollars, and another where they are in percentages.
Deduction Template Object is a mix of a [JSON schema](https://json-schema.org/) which contains instructions on how to create a deduction as well as holds the values of the template itself.
| attribute | type | description |
| :-------------------- | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `companyID` | string | ID of Company the Deduction Template is created for |
| `deductionTemplateID` | string | ID of Deduction Template |
| `contribution_type` | object | Contains the contribution\_type that was used to create this deduction. If `const`, then this field cannot be changed |
| `override_type` | object | Contains the override\_type that was used to create this deduction. If `const`, then this field cannot be changed |
| `value` | object | Contains the amount set for either `employee_contribution` or `employer_contribution` while creating the deduction template. If an amount is set, will contain a `default` value. |
| `required` | array | Contains a list of fields that are required to be passed when creating a Deduction |
| `custom_name` | object | Contains the name of the Deduction Template. This name appears on paystubs when a Deduction created from this template is applied to an Employee Check. |
| `deduction_type` | object | Contains the deduction\_type set for this Deduction Template |
| `additional_fields` | object | Some deduction types like HSA, have additional properties apart from employee and employer contributions. This field is used to provide information on those fields |
```json theme={null}
{
"companyID": "fc235f012bae46aa8a08",
"deductionTemplateID": "61d12d38db7df",
"employee_contribution": {
"properties": {
"contribution_type": {
"const": "dollars"
},
"override_type": {
"const": "overridable"
},
"value": {
"type": "number",
"default": 52.16
}
},
"type": "object",
"required": [
"value"
]
},
"additional_fields": {
"properties": {
"hsa_type": {
"const": "family"
}
},
"type": "object"
},
"custom_name": {
"const": "Test HSA"
},
"deduction_type": {
"const": "hsa"
}
}
```
# Delete Deduction
Source: https://docs.zeal.com/reference/employee-checks/deductions/delete-deduction
openapi/employee-checks.json delete /deductions
Delete a deduction attached to an employee check.
# Get Deduction
Source: https://docs.zeal.com/reference/employee-checks/deductions/get-deduction
openapi/employee-checks.json get /deductions
Retrieve a specific deduction attached to an employee check.
# Get Deduction Template
Source: https://docs.zeal.com/reference/employee-checks/deductions/get-deduction-template
openapi/employee-checks.json get /deductionTemplate
Get a Deduction Template for a company.
# Get Deduction Template Definitions
Source: https://docs.zeal.com/reference/employee-checks/deductions/get-deduction-template-definitions
openapi/employee-checks.json get /deductionTemplateDefinitions
Retrieve the JSON schema definition for a deduction type, describing every field allowed when creating a Deduction Template.
Zeal's deduction system lets you model additional withholding - 401(k), HSA, garnishments, and more - on top of standard tax withholdings. First define the rules by creating a **Deduction Template**, then attach a **Deduction** to a specific employee check. Each deduction type has a corresponding JSON-schema definition that tells you exactly which fields are required and what values are accepted.
### Reading the JSON Schema
The definition schema uses three value constraint types:
| Constraint | Meaning |
| ---------- | ----------------------------------------------------------- |
| `const` | The field must be exactly that value |
| `enum` | The field must be one of the listed values |
| `type` | The field must match the given JSON type (e.g., `"number"`) |
The `required_template_fields` property is **not** included in the Deduction Template request body. Instead, it tells you which fields will be required later when you create an actual Deduction using that template.
### Understanding `override_type`
Contribution objects typically include an `override_type` field that controls how the value is handled at check time:
| Value | Behavior |
| ------------- | ------------------------------------------------------------------------------------------------------- |
| `final` | The value set in the template is locked and cannot be changed when creating a deduction. |
| `needs_input` | No default value is stored in the template. You must supply the value each time you create a deduction. |
| `overridable` | A default value is stored in the template but can be overridden when creating a deduction. |
# Types of Deductions
Source: https://docs.zeal.com/reference/employee-checks/deductions/types-of-deductions
The following is a list of Deductions (both pre-tax and post-tax) that Zeal supports.
The following is a list of Deductions (both pre-tax and post-tax) that Zeal supports:
`401k` - (Pre Tax) A 401(k) plan is a tax-qualified, defined-contribution pension account that provides for pretax retirement savings.
`hsa` - (Pre Tax) A health savings account (HSA) is a tax-advantaged medical savings account enrolled in a high-deductible health plan. Funds accumulate and can be used to pay for qualified medical expenses without tax liabilities.
`garnishment` - **Deprecated** (sunset October 15, 2026). Use the [Garnishments API](/reference/garnishments/create-garnishment) instead. (Post Tax) A Wage Garnishment is a court-mandated withholding of an employee's earnings from a paycheck for use toward debts. Common sources include: Child support, federal debt, state debt, student loans, and credit card debt.
`miscellaneous` - (Post tax) Use this type for a generic post-tax deduction on the employee check.
`section_125` - (Pre-tax) A benefit belonging to a Section 125 plan that allows employees to choose between different types of qualified benefits.
`roth_401k` - (Post Tax) The Roth 401(k) is a defined-contribution pension account that requires that the income tax be paid immediately, so the employee's real net income is reduced by the amount earmarked for savings.
`403(b)` - (Pre Tax) A 403(b) plan (tax-sheltered annuity plan or TSA) is a retirement plan offered by public schools, non-profit organizations, and government entities It's similar to a 401(k) plan maintained by a for-profit entity. Just as with a 401(k) plan, a 403(b) plan lets employees defer some of their salary into individual accounts.
`simple_ira` - (Pre Tax) A SIMPLE IRA plan (Savings Incentive Match PLan for Employees) allows employees and employers to contribute to traditional IRAs set up for employees by usually smaller businesses or companies.
`roth_ira` - (Post-tax) A Individual Retirement Account to which you contribute after-tax dollars. Your contributions and earnings can grow tax-free, and you can withdraw them tax- and penalty-free after age 59½ and once the account has been open for five years
`calsavers` - (Post-tax) California's state-mandated retirement savings program for employees who don't have access to a workplace retirement plan. Employers with five or more employees are required to either offer a qualified retirement plan or register for CalSavers and facilitate payroll deductions. The program uses Roth IRAs, meaning contributions are made with after-tax dollars and qualified withdrawals are tax-free. Contributions are not tax-deductible for employees, and employers are not required to contribute or pay any fees.
`dependent_care_benefit` - (Pre Tax) Dependent care benefits refer to specific benefits that are provided by employers to their employees in the care of their dependents. Dependent care benefits are under a bigger umbrella of the employee benefits system administered by the Internal Revenue Service (IRS). A list of dependent care benefits can be found in the W-2 Form, box 10
`employer_sponsored_health_coverage` - (Pre Tax) The Affordable Care Act requires employers to report the cost of coverage under an employer-sponsored group health plan on an employee's Form W-2, Wage and Tax Statement, in Box 12, using Code DD. The amount reported does not affect tax liability, as the value of the employer contribution continues to be excludable from an employee's income and is not taxable. This reporting is for informational purposes only, to show employees the value of their health care benefits.
Note - `employer_sponsored_health_coverage` needs both the employer and employee contributions. It's expected that the employee contributions will be set to 0 through the API
# Update Deduction
Source: https://docs.zeal.com/reference/employee-checks/deductions/update-deduction
openapi/employee-checks.json patch /deductions
Update a deduction attached to an employee check.
# Create Bulk Employee Checks
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/create-bulk-employee-checks
openapi/zeal-api.json post /employeeChecks
Create a batch of up to 100 employee checks in a single request as part of a payroll run.
# Create Employee Check
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/create-employee-check
openapi/employee-checks.json post /employeeCheck
Create a new payroll check for a W-2 employee by submitting shifts, a reporting period, and a check date.
Employee checks are the core payroll object in Zeal. Each check represents a single payment to a W-2 employee and contains the shifts (units of work and earnings) that determine gross pay, tax withholding, and net disbursement. See the [Reporting Period Object](/reference/employee-checks/reporting-periods/reporting-period-object) and [Shift Object](/reference/employee-checks/shifts/shift-object) for the objects this endpoint references.
# Delete Employee Check
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/delete-employee-check
openapi/employee-checks.json delete /employeeCheck
Delete a pending employee check.
Only checks with a `status` of `pending` can be deleted.
# Download Paystub PDF
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/download-paystub-pdf
openapi/zeal-api.json get /paystub/company/{companyID}/check/{employeeCheckID}
Fetch a PDF of a paystub corresponding to a processed employee check.
# Employee Check Object
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/employee-check-object
The Employee Check object represents a paycheck for an employee, including pay, taxes, deductions, and disbursement details.
| attribute | type | description |
| :----------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| employeeCheckID | string | Employee Check ID |
| employerCheckID | string | ID of employer check that contains this employee check |
| status | string | Holds one of the following values: `pending` `pre-processed` `processed` `voided` `failed` |
| is\_salary | boolean | Whether this check was created by Zeal's Autopilot Salary feature. See [The Employee Object](/reference/employees/the-employee-object) for more information about Autopilot |
| employeeID | string | Zeal Employee ID |
| companyID | string | Zeal Company ID |
| check\_date | string | Date of Check Date for this employee check, in the ISO-8601 date format YYYY-MM-DD |
| approval\_required | boolean (optional) | Whether manual approval is required for this check or not. By default, Zeal automatically processes the check the day before the check date. However, if approval is required and the check is not approved by time of processing, Zeal will **NOT** process the check |
| approved | boolean (optional) | Whether this check has been manually approved or not (only relevant if `approval_required` is true) |
| first\_name | string | First name of the employee this check is for |
| middle\_initial | string | Middle initial of the employee this check is for |
| last\_name | string | Last name of the employee this check is for |
| reportingPeriodID | string | Reporting Period ID |
| disbursement | object | This object includes information regarding how the net pay is disbursed to the employee.
Zeal supports 6 disbursement methods:
Direct Deposit, Download Check, Physical Check, Prepaid, Paycards (Early Access), and Instant Pay (Early Access).
More information on these can be found at the bottom of the page.
Show disbursement fields:
**method** (type: string, default: `direct_deposit`)
**history** (type: array) Provides an array of transaction updates
**status** (type: string) Provides an up-to-date status of the payment. The `status` will hold one of the following values:
`pending`: Status of all checks until net pay has been started
`settled` - Funds have successfully settled in employee's account
`void` - When an Employer pays out the wrong person or the wrong amount and wants to void the check
`returned` - Net pay did not successfully get disbursed
`refunded` - Status of checks that failed but then the employer wants to pay out in-house (only applicable to direct deposit payments)
`canceled` - The check got canceled due to going to an inactive user or having a transaction going to a watchlist match (only applicable to direct deposit payments) |
| gross\_pay | number | Gross pay for employee based on shifts |
| net\_pay | number | Net pay for employee (total pay after taxes) |
| deductions | array | List of deductions object applied to this employee check. See [The Deduction Object](/reference/employee-checks/deductions/deduction-object) |
| taxes | array | List of tax breakdown *(processed check)*.
Show taxes fields:
`name` - Name of the specific tax parameter
`paidBy` - Specifies whether this was withheld by employee or employer
`codename` - The specified code of the tax parameter
`amount` - Amount of tax withheld |
| total\_employee\_taxes | number | Total amount of employee taxes *(processed check)* |
| total\_employer\_taxes | number | Total amount of employer taxes *(processed check)* |
| totals | object | Object displaying the following totals:
Show totals fields:
`gross_earnings` - Total gross earnings of the check
`gross_pay` - Total gross pay of the check
`net_pay` - Total net pay of the check
`employer_taxes` - Total employer taxes of the check
`employee_deductions` - Total amount of employee deductions applied to the check, if any
`employee_garnishments` - Total amount of employee garnishments applied to the check, if any
`employer_deductions` - Total amount of employer deductions applied to the check, if any
`company debit` - The total amount to be debited from the company bank account for this check
`company_cash_requirement` - The total requirement amount for the company to fulfill the check |
| metadata | object | Custom object you can attach to the employee check object. This is useful for storing additional information about the object in a custom, structured format. See [Metadata](/reference/introduction/metadata) |
| shifts | array | List of shifts objects associated with this employee check. |
| flsa\_ot\_recommendation | boolean | If set to true, we will automatically convert the check to include our OT recommendation at the time of processing **NOTE: Only applicable for FLSA Overtime Policy** |
| speed | string | The ACH speed of the check, accepts `two_day`, `one_day`, `one_day_no_reserve`, or `zero_day_no_reserve` as values **(Early Access)** |
| triggered | boolean | Whether a disbursement has been triggered. Only applicable if disbursement method is `paycard` or `instant_pay` |
| triggered\_at | datetime | Timestamp of when the disbursement was triggered, in the ISO-8601 format in UTC. |
| currency | string | Currency of the employee check. One of `USD` (US payroll) or `CAD` (Canadian payroll) **NOTE: `CAD` is only applicable for Canadian Payroll (Early Access)** |
## Types of Disbursement Methods
**Direct Deposit**: The most convenient disbursement type is to do a direct deposit into the employee's bank account, from the employers. In this case, Zeal will include the employee net pay in the Company Debit number of the employer check (i.e. net pay is debited from the employer's bank account.
The net pay is deposited into the employee bank account at check date.
**Download check**: Checks are useful for certain employees who prefer to be paid in checks instead of direct deposits. We do not include net pay from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is "download check").
Net pay is only taken out of the employers bank account when the employee cashes the check. The account / routing number is that of the employers.
The link for downloading the check becomes available by check date on the employee dashboard.
**Physical check**: For employees where net pay speed delivery is not an issue, and who prefer to be paid with a physical, mailed check instead of the download check or direct deposit methods. We do not include the net pay amount from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is "phsyical check").
Net pay is only taken out of the employers bank account when the employee cashes the check. The account / routing number is that of the employers.
The physical check is created on the check date, and sent to the home address listed for the employee in Zeal. Its arrival time will depend on the location of the employee.
**Prepaid**: Prepaid is used when the employer does want to use direct deposit, but instead has an alternate method of paying their employees. In that case, Zeal does not include net pay from this employee check in the Company Debit number of the employer check (i.e. net pay is not debited from the employer's bank account if employee check is prepaid). Instead the employer is shown the net pay they owe their employees after taking out the appropriate taxes.
The employer is responsible for disbursing net pay outside of Zeal.
**Paycard**: If an employee has a paycard, the `paycard` disbursement method can be used to direct funds to the existing paycard. This allows for instantaneous payout and does not depend on ACH timings and delays. **Note: This is only available for Paycards product (Early Access)**
**Instant Pay**: If an employee has an Instant Pay wallet, the `instant_pay` disbursement method can be used to direct funds to their wallet. This allows for instantaneous payout and does not depend on ACH timings and delays. **Note: This is only available for Instant Pay product (Early Access)**
# Get Employee Check by ID
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/get-employee-check-by-id
openapi/zeal-api.json get /employeeCheck
Retrieve a single employee check by its employeeCheckID.
This is the same underlying route as [Get Employee Checks by Employee](/reference/employee-checks/employee-checks/get-employee-checks-by-employee), which lists checks for an employee instead of looking up a single check - the API doesn't distinguish these with separate routes, so each page documents the query parameters for its own intended usage. This page's usage: pass `companyID` and `employeeCheckID` to look up a single check.
# Get Employee Checks by Employee
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/get-employee-checks-by-employee
openapi/employee-checks.json get /employeeCheck
Retrieve employee checks for a given employee, optionally filtered by status or reporting period.
This is the same underlying route as [Get Employee Check by ID](/reference/employee-checks/employee-checks/get-employee-check-by-id), which looks up a single check instead of listing by employee - the API doesn't distinguish these with separate routes, so each page documents the query parameters for its own intended usage.
# Update Employee Check
Source: https://docs.zeal.com/reference/employee-checks/employee-checks/update-employee-check
openapi/employee-checks.json patch /employeeCheck
Update a pending employee check - approve it, change the check date, or update the disbursement method.
Only checks with a `status` of `pending` can be updated. Once a check enters processing, it can no longer be modified via this endpoint.
# Get Upcoming Regular Payroll
Source: https://docs.zeal.com/reference/employee-checks/payroll-run/get-upcoming-regular-payroll
openapi/employee-checks.json get /payroll/regular
Get the upcoming regularly scheduled check date for a company and its associated reporting period.
# Get All Reporting Periods
Source: https://docs.zeal.com/reference/employee-checks/reporting-periods/get-all-reporting-periods
openapi/employee-checks.json get /reportingPeriod/
List all reporting periods for a company, optionally filtered by pay schedule.
# Get Reporting Period by Date Range
Source: https://docs.zeal.com/reference/employee-checks/reporting-periods/get-reporting-period-by-date-range
openapi/employee-checks.json get /reportingPeriod
Retrieve the reporting period containing a given date range and pay schedule.
Zeal returns the corresponding reporting period with the given `pay_schedule` that is contained within the given start and end dates.
To find the correct reporting period using this endpoint, ensure that `searchStart` is less than or equal to the `start` date in the response, and that `searchEnd` is greater than or equal to the `end` date in the response.
This uses the same underlying endpoint as [Get Reporting Period by ID](/reference/employee-checks/reporting-periods/get-reporting-period-by-id) - see that page for the formal parameter schema.
# Get Reporting Period by ID
Source: https://docs.zeal.com/reference/employee-checks/reporting-periods/get-reporting-period-by-id
openapi/employee-checks.json get /reportingPeriod
Retrieve a single reporting period for a company by its reportingPeriodID.
# Pay Frequency, Reporting Periods and Check Dates
Source: https://docs.zeal.com/reference/employee-checks/reporting-periods/pay-frequency-reporting-periods-and-check-dates
How pay frequency, reporting periods, and check dates work in Zeal, and how they affect payroll timing.
## Pay Frequency/Schedule
The pay frequency for an employee is set during the [creation of the employee](/reference/employees/create-employee). The different options are:
* Daily: This employee gets paid every day.
* Weekly: This employee gets paid every week.
* Biweekly: This employee gets paid every other week.
* Semimonthly: This employee gets paid twice a month.
* Monthly: This employee gets paid once a month.
This information helps Zeal tax this employee correctly.
***
## Reporting Period
A [Reporting Period](/reference/employee-checks/reporting-periods/reporting-period-object) is a range of dates in which work was performed. Each [**Employee Check**](/reference/employee-checks/employee-checks/create-employee-check) submitted to Zeal must have an associated reporting period. Zeal hosts all possible reporting periods for every type of pay schedule.
### Note
The reporting period spans from the `start` to the `end`, BOTH dates **inclusive**. For example, the reporting period with the start date of `2025-08-02` and the end date of `2025-08-08` spans the 168-hour period from August 2nd at 12:00:01 AM to August 8th at 11:59:59 PM.
Zeal supports the following types of reporting periods (note that all dates are INCLUSIVE):
`daily` : Zeal hosts 365 daily reporting periods per year. For example:
* `2025-08-01` - `2025-08-01`: August 1st
* `2025-08-02` - `2025-08-02`: August 2nd
* `2025-08-03` - `2025-08-03`: August 3rd
* ...
`weekly`: Zeal hosts 52 weekly reporting periods per year. For example:
* `2025-08-02` - `2025-08-08`: August 2nd - August 8th
* `2025-08-03` - `2025-08-09`: August 3rd - August 9th
* ...
`biweekly`: Zeal hosts 26 biweekly (once every two weeks) reporting periods per year. For example:
* `2025-08-02` - `2025-08-15`: August 2nd - August 15th
* `2025-08-03` - `2025-08-16`: August 3rd - August 16th
* ...
`semimonthly`: Zeal hosts 24 semimonthly (twice per month) reporting periods per year.
> Note: `semimonthly` is different from `biweekly`
For example:
* `2025-08-01` - `2025-08-15`: August 1st - August 15th
* `2025-08-16` - `2025-08-31`: August 16th - August 31st
* `2025-09-01` - `2025-09-15`: September 1st - September 15th
* ...
`monthly`: Zeal hosts 12 monthly reporting periods per year. Date ranges can start on the first of every month or on the 15th of every month. For example:
* `2025-08-01` - `2025-08-31`: August 1st - August 31st
* `2025-08-15` - `2025-09-14`: August 15th - September 14th
* `2025-09-01` - `2025-09-31`: September 1st - September 31st
* ...
This information helps Zeal tax this employee correctly.
***
## Check Date
A check date is a date on which the employee should receive their money. The check date is extremely important and determines when the check should be sent to the employee. Each [Employee Check submitted to Zeal](/reference/employee-checks/employee-checks/create-employee-check) must have an associated viable check date. Zeal will process the check 2 non-holiday business days before the check date to ensure the employee receives the money by the check date.
See how to [create an Employee Check](/reference/employee-checks/employee-checks/create-employee-check).
### Note
The time it takes for money to clear the employee's bank account depends on the employee's bank.
# Reporting Period Object
Source: https://docs.zeal.com/reference/employee-checks/reporting-periods/reporting-period-object
The Reporting Period object represents a date range for a single pay cycle. Learn its schema and how it's used when creating employee payroll checks.
A **Reporting Period** represents a date range that corresponds to a single pay cycle for a company. Every employee check you create must reference a `reportingPeriodID`, which tells Zeal which pay cycle the payment belongs to. Zeal generates reporting periods automatically based on the company's configured pay schedule, so you typically look them up rather than create them.
You can fetch the full list of reporting periods for a company, look up a specific period by its `reportingPeriodID`, or retrieve the upcoming regular payroll period and check date in a single call.
***
## Reporting Period Schema
The unique identifier for this reporting period. Pass this value as `reportingPeriodID` when creating an employee check.
The pay schedule associated with this period (e.g., `weekly`, `biweekly`, `semimonthly`, `monthly`).
The first day of the pay period in `YYYY-MM-DD` format.
The last day of the pay period in `YYYY-MM-DD` format.
See [Get Reporting Period by ID](/reference/employee-checks/reporting-periods/get-reporting-period-by-id), [Get All Reporting Periods](/reference/employee-checks/reporting-periods/get-all-reporting-periods), and [Get Upcoming Regular Payroll](/reference/employee-checks/payroll-run/get-upcoming-regular-payroll) for the full request/response detail on each field.
***
## Using `reportingPeriodID` in Employee Checks
Once you have a `reportingPeriodID`, include it as a required field when calling `POST /employeeCheck` to create a new employee check. The reporting period anchors the check to the correct pay cycle so Zeal can apply the right tax tables, deadlines, and filing periods.
```json theme={null}
{
"companyID": "{companyID}",
"employeeID": "{employeeID}",
"reportingPeriodID": "5eb317a40d1158d5ddcb6895",
"check_date": "2024-02-19",
"shifts": [
{
"time": "2024-02-01T09:00:00Z",
"hourly": {
"hours": 80
}
}
]
}
```
# Add Shifts to Existing Check
Source: https://docs.zeal.com/reference/employee-checks/shifts/add-shifts-to-check
openapi/employee-checks.json post /shifts
Add one or more shifts to an existing, pending employee check.
See the [Shift Object](/reference/employee-checks/shifts/shift-object) for the shift schema.
# Delete Pending Shifts
Source: https://docs.zeal.com/reference/employee-checks/shifts/delete-pending-shifts
openapi/employee-checks.json delete /shifts
Delete a shift from a pending employee check.
Only shifts on a check with a `status` of `pending` can be deleted.
# Get Shift Information
Source: https://docs.zeal.com/reference/employee-checks/shifts/get-shift-information
openapi/employee-checks.json get /shifts
Retrieve a specific shift by its shiftID.
# Shift Object
Source: https://docs.zeal.com/reference/employee-checks/shifts/shift-object
Learn the Shift Object schema for describing work and earnings on an employee check.
A shift is the unit of earnings in Zeal's payroll system. Every employee check must contain at least one shift. Shifts can be provided when creating an employee check ([`POST /employeeCheck`](/reference/employee-checks/employee-checks/create-employee-check)) or added to an existing pending check via [`POST /shifts`](/reference/employee-checks/shifts/add-shifts-to-check).
Each shift carries a `time` field (an ISO-8601 datetime indicating when the work was performed) plus one nested earning-type object - for example `hourly`, which takes `hours` (required), an optional `wage` override, and an optional `custom_name` label:
```json theme={null}
{
"time": "2024-02-01T09:00:00Z",
"hourly": {
"hours": 8,
"wage": 25,
"custom_name": "Regular hours"
}
}
```
If `wage` is omitted, Zeal uses the employee's `default_wage`.
ISO-8601 UTC timestamp of when the shift was last modified. Returned on
persisted shifts (for example from [Get Shift
Information](/reference/employee-checks/shifts/get-shift-information)). Use it
to identify shifts that were recently changed.
See [Add Shifts to Existing Check](/reference/employee-checks/shifts/add-shifts-to-check), [Get Shift Information](/reference/employee-checks/shifts/get-shift-information), and [Update Pending Shifts](/reference/employee-checks/shifts/update-pending-shifts) for the full request/response schema, including any other earning types your account has enabled.
# Update Pending Shifts
Source: https://docs.zeal.com/reference/employee-checks/shifts/update-pending-shifts
openapi/employee-checks.json patch /shifts
Update the time and earning components of shifts on a pending employee check.
Only shifts on a check with a `status` of `pending` can be updated.
# Create Employee Deduction Template
Source: https://docs.zeal.com/reference/employee-deduction-templates/create-employee-deduction-template
openapi/zeal-api.json post /employee-deduction-templates
Create an employee deduction template, such as a 401(k), HSA, or miscellaneous deduction.
Creates a new deduction template for an employee. Returns the created [Employee Deduction Template](/reference/employee-deduction-templates/get-employee-deduction-template) object.
# Delete Employee Deduction Template
Source: https://docs.zeal.com/reference/employee-deduction-templates/delete-employee-deduction-template
openapi/zeal-api.json delete /employee-deduction-templates/{deductionTemplateID}
Delete an employee deduction template by its deductionTemplateID.
Deletes an existing Employee Deduction Template identified by its `deductionTemplateID`.
# Get Employee Deduction Template
Source: https://docs.zeal.com/reference/employee-deduction-templates/get-employee-deduction-template
openapi/zeal-api.json get /employee-deduction-templates/{deductionTemplateID}
Retrieve a single employee deduction template by its deductionTemplateID.
Returns a single Employee Deduction Template object identified by its `deductionTemplateID`.
The Employee Deduction Template object contains the following fields:
| attribute | type | description |
| ---------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| deductionTemplateID | string | ID of this template. |
| companyID | string | ID of the company related to this template. |
| employeeID | string | ID of the employee related to this template. |
| custom\_name | string | Human-readable name for the deduction template. |
| deduction\_type | string (enum) | One of `401k`, `403b`, `dependent_care_benefit`, `employer_sponsored_health_coverage`, `garnishment` (**deprecated** — sunset October 15, 2026; use [Create Garnishment](/reference/garnishments/create-garnishment)), `hsa`, `miscellaneous`, `roth_401k`, `roth_ira`, `section_125`, `simple_ira`. |
| effective\_start\_date | string (date) | Date the template starts becoming effective. |
| employee\_contribution\_amount | number | Default dollar amount contributed by the employee for deductions. |
| employer\_contribution\_percentage | number | Default percentage of the employee's pay contributed for deductions. |
| external\_id | string | ID in an external system related to the template. |
# List Employee Deduction Templates
Source: https://docs.zeal.com/reference/employee-deduction-templates/list-employee-deduction-templates
openapi/zeal-api.json get /employee-deduction-templates
Retrieve a paginated list of employee deduction templates, optionally filtered by company, employee, or template fields.
Returns a paginated array of [Employee Deduction Template](/reference/employee-deduction-templates/get-employee-deduction-template) objects matching the supplied filters.
# Update Employee Deduction Template
Source: https://docs.zeal.com/reference/employee-deduction-templates/update-employee-deduction-template
openapi/zeal-api.json patch /employee-deduction-templates/{deductionTemplateID}
Update fields on an existing employee deduction template by deductionTemplateID.
Updates an existing Employee Deduction Template. Returns the updated [Employee Deduction Template](/reference/employee-deduction-templates/get-employee-deduction-template) object.
# Create Account Setup Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-account-setup-link
openapi/zeal-api.json post /employees/account_information
This endpoint provides a link for an employee to complete Account Setup.
# Create Bank Account Collection Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-bank-account-collection-link
openapi/zeal-api.json post /employees/bank_information
Create a link for an employee to submit their bank account information.
# Create Custom Paperwork Link (Early Access)
Source: https://docs.zeal.com/reference/employee-onboarding/create-custom-paperwork-link
openapi/zeal-api.json post /employees/custom_paperwork
Create a link for an employee to complete custom paperwork in Zeal.
# Create Employee ID Upload Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-employee-id-upload-link
openapi/zeal-api.json post /employees/id_upload_link
Create a shareable link for an employee to submit their ID verification information.
# Create I9 Link (Early Access)
Source: https://docs.zeal.com/reference/employee-onboarding/create-i9-link
openapi/zeal-api.json post /employees/i9
Create a link for an employee to complete the I-9 Form in Zeal.
# Create Instant Pay Employee Enrollment Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-instant-pay-enrollment-link
openapi/zeal-api.json post /employees/instant-pay
Create an enrollment link for an employee to enroll in Instant Pay.
# Create Paycard Enrollment Link (Early Access)
Source: https://docs.zeal.com/reference/employee-onboarding/create-paycard-enrollment-link
openapi/zeal-api.json post /employees/paycard
This endpoint provides a link for an employee to complete Paycard Enrollment Link.
# Create Profile Information Collection Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-profile-information-collection-link
openapi/zeal-api.json post /employees/profile_information
Create a link for an employee to submit profile information in Zeal.
# Create W4 Link
Source: https://docs.zeal.com/reference/employee-onboarding/create-w4-link
openapi/zeal-api.json post /employees/w4
Create a link for an employee to complete their W-4 tax form in Zeal.
# Generate Employee Onboarding Link
Source: https://docs.zeal.com/reference/employee-onboarding/generate-employee-onboarding-link
openapi/zeal-api.json post /employees/onboard
Generates an expirable link to Zeal's employee payroll onboarding for a specified employee.
# Generate Employee Tax Parameter Definitions
Source: https://docs.zeal.com/reference/employee-onboarding/generate-employee-tax-parameter-definitions
openapi/zeal-api.json post /employees/getTaxParameterDefinitions
Retrieve all tax parameters used for withholding calculations.
# Get Employee Requirements
Source: https://docs.zeal.com/reference/employee-onboarding/get-employee-requirements
openapi/zeal-api.json get /employeeRequirements
Get additional tax requirements for an employee in Zeal.
# Get Employee Requirements Link
Source: https://docs.zeal.com/reference/employee-onboarding/get-employee-requirements-link
openapi/zeal-api.json get /employeeRequirements/link
Get links to submit additional tax requirements for an employee in Zeal (Early Access).
# Get Employee Tax Parameter Summary
Source: https://docs.zeal.com/reference/employee-onboarding/get-employee-tax-parameter-summary
openapi/zeal-api.json post /employees/getTaxParameterSummary
Retrieve a list of an employee's tax withholding parameters.
# Get I9 Status (Early Access)
Source: https://docs.zeal.com/reference/employee-onboarding/get-i9-status
openapi/zeal-api.json get /employees/getI9Status
Get the status of an I9's completion in Zeal.
# Send Employee Onboarding Link
Source: https://docs.zeal.com/reference/employee-onboarding/send-employee-onboarding-link
openapi/zeal-api.json post /sendLink
Sends an employee onboarding link to the specified employee's email in Zeal.
# Set Employee Tax Parameters
Source: https://docs.zeal.com/reference/employee-onboarding/set-employee-tax-parameters
openapi/zeal-api.json post /employees/setTaxParameters
Set an employee's tax withholding parameters.
# Set Onboarded Status to True
Source: https://docs.zeal.com/reference/employee-onboarding/set-onboarded-status-to-true
openapi/zeal-api.json post /employees/setOnboardedStatusToTrue
Set an employee as onboarded.
# Upload Employee Government ID
Source: https://docs.zeal.com/reference/employee-onboarding/upload-employee-government-id
openapi/zeal-api.json post /employees/id
Uploads a government issued ID for a specified employee in Zeal.
# Create Employee
Source: https://docs.zeal.com/reference/employees/create-employee
openapi/zeal-api.json post /employees
Create one or more W-2 employees under a company in Zeal.
See the [Employee Object](/reference/employees/the-employee-object) for the full field reference.
# Employee Requirements Object
Source: https://docs.zeal.com/reference/employees/employee-requirements-object
The Zeal object representing a requirement for an employee, such as a form to be completed.
| attribute | type | description |
| :---------------------- | :----- | :-------------------------------------- |
| `employeeRequirementID` | string | ID of the employee requirement |
| `companyID` | string | ID of company |
| `employeeID` | string | ID of employee |
| `date` | string | Date when the requirement was created |
| `formTemplateID` | string | ID of the form template |
| `workLocationID` | string | ID of the work location |
| `jurisdiction` | string | Jurisdiction of the requirement |
| `type` | string | Type of requirement |
| `status` | string | Status of requirement: `OPEN`, `CLOSED` |
```json theme={null}
{
"employeeRequirementID": "8bafd033-55c7-4edc-b671-xxxxxxxxxxxx",
"type": "FORM",
"status": "OPEN",
"workLocationID": "635ae06ac6cf7b0f2b1xxxxx",
"jurisdiction": "KY",
"formTemplateID": "form-ebc648e7-0b11-424a-b7fb-xxxxxxxxxxxx",
"employeeID": "657b627deca2a90023bxxxxx",
"companyID": "24b5b29f07924840b119c34c135xxxxx",
"date": "2023-12-14T20:52:18.280Z"
}
```
# Get Employee Information
Source: https://docs.zeal.com/reference/employees/get-employee-information
openapi/zeal-api.json get /employees
Retrieve key information about a single W-2 employee by employeeID.
This request uses the `employeeID` attribute to return key information about the employee, contained within the [Employee Object](/reference/employees/the-employee-object). This is the same underlying route as [Get Employees](/reference/employees/get-employees), which lists/filters instead of looking up a single employee - the API doesn't distinguish these with separate routes, so each page documents the query parameters for its own intended usage.
This applies to W-2 employees. For 1099 contractors, use the [Get Contractor Information](/reference/contractors/get-contractor-information) request instead.
## Returns
| attribute | type | description |
| --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | Response status |
| data | object | Retrieves the [Employee Object](/reference/employees/the-employee-object) for the requested employee |
| errors | array | Contains a list of error objects which consists of: `message` (error message) and `code` (error code, see [Error codes](https://docs.zeal.com/reference/introduction/error-codes)) |
# Get Employees
Source: https://docs.zeal.com/reference/employees/get-employees
openapi/zeal-api.json get /employees
Retrieve summarized information for all employees under a company, with optional filters.
Create a request using the `companyID` attribute to return key summarized information for all employees under the indicated employer.
This uses the same underlying endpoint as [Get Employee Information](/reference/employees/get-employee-information), which looks up a single employee by `employeeID` instead of listing/filtering - the API does not distinguish these with separate routes, so the query parameters accepted differ by intended usage. This page's usage: pass `companyID` and any of the optional filters below (omit `employeeID`) to get a filtered list of employees.
# The Employee Object
Source: https://docs.zeal.com/reference/employees/the-employee-object
The Employee Object represents a W-2 employee for a given company.
The Employee Object represents a W-2 employee for a given company.
| attribute | type | description |
| ----------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| employeeID | string | Zeal Employee ID |
| companyID | string | Zeal Company ID of the employer |
| onboarded | boolean | Whether the employee has been onboarded onto Zeal or not |
| employment\_status | string | Employment status of the employee. Holds one of the following values:`live`: This employee currently works for this company and will receive payroll`leave`: This employee is "On Leave"`terminated`: This employee has been "Terminated". If terminated, must have `term_date`. (see below) |
| term\_date | string | Termination Date of the employee. The termination date is the day on which the employee and the employer end their relationship and is formatted as a date (YYYY-MM-DD)**NOTE: This field is required to mark an Employee as terminated if opted into Health Insurance (Early Access)** |
| term\_reason | string | Termination reason of the employee. Holds one of the following values: `voluntary`: This employee has voluntarily left the company `involuntary`: This employee has involuntarily left the company `death`: This employee is no longer with the company due to death `misconduct`: This employee is no longer with the company due to misconduct**NOTE: This field is required to mark an Employee as terminated if opted into Health Insurance (Early Access)** |
| benefits\_class | string | Class of employee used for Health Insurance eligibility. Holds one of the following values:`Full-Time`, `Part Time`, `Executive`, `VP`, `IT Staff`, `Eligible - No ER Contribution`: Eligible for benefits and will receive an enrollment link`Ineligible`: **(Default)** Not eligible for benefits and will not receive an enrollment linkThere may be additional fields based on Health Insurance configuration.**NOTE: This field is only required if opted into Health Insurance (Early Access)** |
| first\_name | string | First name of the employee |
| last\_name | string | Last name of the employee |
| title | string | Title of employee |
| dob | string | Date of birth of the employee |
| start\_date | string | Start Date of employee (also known as hire date). This is the first day that this employee works in return for wages and is formatted as a date (YYYY-MM-DD). Zeal uses this date for new hire reporting. |
| email | string | Email of employee |
| address | string | Residential Street address of the employee |
| address\_line2 | string | Residential Street Address Line 2 of employee (i.e. apt numbers, suite no., etc.) |
| city | string | Residential City of employee |
| state | string | Residential State of employee (US). Used when `country` is `US` |
| zip | string | Residential Zip code of the employee (US). Used when `country` is `US` |
| country | string | Country of the employee residence. One of `US` or `CA`. Defaults to `US` **NOTE: `CA` is only applicable for Canadian Payroll (Early Access)** |
| province | string | Canadian province/territory of the employee residence (2-letter abbreviation: `AB`, `BC`, `MB`, `NB`, `NL`, `NS`, `NT`, `NU`, `ON`, `PE`, `QC`, `SK`, `YT`). Used when `country` is `CA` **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| postal\_code | string | Canadian postal code of the employee residence. Used when `country` is `CA` **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| phone\_number | string | Phone number of employee. Formatted with "+1" country code (e.g. `+18214370987`) |
| default\_pay\_schedule | string | Default pay schedule of the employee. See the different options [here](/reference/employee-checks/reporting-periods/pay-frequency-reporting-periods-and-check-dates) |
| default\_wage | number | Default wage of the employee |
| default\_ot\_wage | number | Wage for overtime pay. Default OT rate is 1.5 times base wage |
| default\_dt\_wage | number | Wage for double time pay. Default DT rate is 2 times base wage |
| ssn | string | Social security number of employee (US). Used when `country` is `US` |
| sin | string | Canadian Social Insurance Number (SIN). Accepts `123456789` or `123-456-789`. Used when `country` is `CA` **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| is\_943 | boolean | Set to `true` if the employee is a farmworker |
| is\_scheduleH | boolean | Set to `true` if the employee falls under the Schedule H category as a household employee |
| is\_owner | boolean | Set to `true` if the employee is an Owner of the business and only receives [Owner's Draw](/docs/earning-components#/) earnings or reimbursements. There will be no tax withheld for this type of employee **Note: Early Access** |
| external\_id | string | External ID for an employee that comes from an employer's HR or other internal systems |
| metadata | object | Custom object you can attach to the employee object. This is useful for storing additional information about the object in a custom, structured format. See [Metadata](https://docs.zeal.com/reference/metadata). |
| workLocationID | string | ID of [Work Location Object](/reference-link/company-location-object) |
| work\_week\_start | string | ISO-8601 date-time with accurate UTC offset depicting the beginning of the work week when the employee begins work **NOTE: Only applicable for FLSA Overtime Policy (Early Access)** |
| is\_salary | boolean | Set to `true` if the employee is salaried |
| salary | number | The annual salary amount of the employee |
| is\_regular | boolean | Set to `true` if the employee should be included in “on-cycle” payroll runs |
| everify\_case\_number | string | Case number of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_further\_action\_notice\_url | string | Further action notice URL link of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_status | string | Holds one of the following values:`IN_PROGRESS`: A case has been created for the worker and e-verify is processing it`PENDING_REFERRAL`: The case received a Tentative Nonconfirmation (TNC) status and the employer must tell e-verify how to proceed`REFERRED`: The case has been referred to an E-verify agency and the worker will get in touch with them`SUCCESS`: The worker is authorized to work in the US`FAILURE`: The worker is not authorized to work in the US`FAILURE_NO_SHOW`: The worker never contacted the E-verify agency to resolve their Tentative Nonconfirmation (TNC) after indicating that they would take action, and are not authorized to work in the US`FAILURE_NO_ACTION`: The worker decided to take no action to resolve their Tentative Nonconfirmation (TNC), and are not authorized to work in the US **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_referral\_date\_confirmation\_url | string | Referral date confirmation URL of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_status\_display | string | Status display of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_ee\_continues\_to\_work\_after\_fnc | boolean | Set to `true` if the employee continues to work after a Final Nonconfirmation **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_er\_shared\_referral\_date\_confirmation\_at | string | Date the employer shared the referral confirmation of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| everify\_status\_updated\_at | string | Status update of the E-Verify request **NOTE: Only applicable for I9/E-Verify (Early Access)** |
| paycard\_requested | boolean | Set to `true`if the contractor has completed paycard enrollment. The paycard may not be successfully provisioned to the contractor yet. **NOTE: Only applicable for Paycards (Early Access)** |
| paycard\_enabled | boolean | Set to `true`if the employee has completed paycard enrollment **NOTE: Only applicable for Paycards (Early Access)** |
| kyc\_status | enum | Holds one of the following values:`null``approved``denied` |
| ssn\_verification\_status | enum | Holds one of the following values:`null``approved``declined` |
| soc\_code | string | The Standard Occupational Classification (SOC) code for the employee, in NN-NNNN format |
| instant\_pay\_enabled | boolean | Set to `true` if the employee has completed instant pay enrollment. **NOTE: Only applicable for Instant Pay (Early Access)** |
```bash bash theme={null}
{
"employeeID": "1234567890",
"companyID": "0987654321",
"onboarded": true,
"employment_status": "live",
"term_date": null,
"first_name": "erlich",
"last_name": "bachman",
"email": "erlich@zeal.com",
"dob": "1999-12-04",
"start_date": "2019-06-04",
"title": "Brand Ambassador",
"working_state": "CA",
"workLocationID": "6247402f38756100224f0a52",
"address": "320 Pancake Hollow Road",
"address_line2": null,
"city": "Highland",
"state": "NY",
"zip": "12528",
"phone_number": "+18214370987",
"default_pay_schedule": "weekly",
"default_wage": 20,
"default_ot_wage": 30,
"default_dt_wage": 40,
"ssn": "123456789",
"is_943": true,
"is_scheduleH": false,
"is_salary": true,
"salary": 100000,
"external_id": "123456789",
"paycard_requested": false,
"paycard_enabled": false,
"kyc_status": "approved",
"ssn_verification_status": null,
"soc_code": "15-1256",
"instant_pay_enabled": true
}
```
# Update Employee Information
Source: https://docs.zeal.com/reference/employees/update-employee-information
openapi/zeal-api.json patch /employees
Update a specific employee record in Zeal.
# Employer Check Object
Source: https://docs.zeal.com/reference/employer-checks/employer-check-object
The Zeal Employer Check represents a payroll run and is only created when checks are sent out (typically the day before a check date).
The Zeal Employer Check represents a payroll run and is only created when checks are sent out (typically the day before a check date). It notably contains employee checks paid during this payroll run and a `totals` object that contains aggregate and sum values across the contained employee checks.
> **📘 IMPORTANT**
>
> A Employer Check Object is created purely based on timing - it could potentially encapsulate 2 employee checks that have different reporting periods, but the same check date.
>
> See Employer Check Object.
| attribute | type | description |
| :------------------ | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `employerCheckID` | string | Employer Check ID |
| `companyID` | string | ID of the Company that owns this employee check |
| `status` | string | When an employer check is processed, employee checks are sent out and tax information is attached to the Employer Check object. This field holds one of the following values: `pending` `pre-processed` `processed` |
| `reporting_periods` | array | List of reporting periods contained in this employer check.
Show child attributes:
**reportingPeriodID** - type: string - description: Reporting Period ID
**start** - type: datetime - description: Start time and date of reporting period
**end** - type: datetime - required: End time and date of reporting period |
| `totals` | object | Totals for this employer check stored in an object.
Show child attributes:
**gross\_pay** - type: float - description: Gross pay for employee (total pay before taxes)
**net\_pay** - type: float - description: Net pay for employee (total pay after taxes = `gross_pay - total_employee_taxes`) - processed check
**total\_employer\_taxes** - type: float - required: Total amount of employer taxes - processed check
**company\_debit** - type: float - description: Total cost for the company (`net_pay + total_employee_taxes + total_employer_taxes`) - processed check
**total\_employee\_taxes** - type: float - description: Total amount of employee taxes for this employer check run - processed check |
| `employee_checks` | array | List of all employee checks. Each object contains information regarding how each employee is paid for this payroll run (i.e. everything found on a paystub and more). See Employee Check Object for all attributes. |
```json theme={null}
{
"employerCheckID": "123456789",
"companyID": "0987654321",
"status": "processed",
"reporting_periods": [
{
"reportingPeriodID": "01739fc4cfd84c2e93dba5e802d1dda1",
"start": "2023-01-05T10:01:00.000Z",
"end": "2023-01-06T10:00:00.000Z"
}
],
"totals": {
"gross_pay": 40,
"net_pay": 26.82,
"total_employer_taxes": 2.8,
"company_debit": 42.8,
"total_employee_taxes": 13.18
},
"employee_checks": [
{
"employeeCheckID": "9827465739",
"status": "processed",
"employeeID": "0987654321",
"check_date": "2020-01-07",
"approval_required": false,
"approved": false,
"metadata": {},
"first_name": "peter",
"last_name": "gregory",
"reportingPeriodID": "01739fc4cfd84c2e93dba5e802d1dda1",
"gross_pay": 40,
"net_pay": 26.82,
"total_employee_taxes": 13.18,
"total_employer_taxes": 2.8,
"taxes": [
{
"name": "Employee Medicare Tax",
"paidBy": "EMPLOYEE_WITHHOLDING",
"amount": 1.16
}
],
"shifts": [
{
"shiftID": "4712c99283304b7b989179aae36b4590",
"status": "processed",
"employeeID": "1234567890",
"time": "2023-01-13T04:00:00Z",
"metadata": {},
"hourly": {
"hours": 2,
"wage": 20
},
"overtime": {
"hours": 2.5,
"wage": 30
}
}
]
}
]
}
```
# Employer CheckID Object
Source: https://docs.zeal.com/reference/employer-checks/employer-checkid-object
The Zeal object identifying an employer check and the reporting periods it contains.
| attribute | type | description |
| :------------------- | :------- | :--------------------------------------------------------------------------- |
| ID of employer check | string | ID of employer check |
| `createdAt` | datetime | Datetime of when this employer check was created (in ISO-8601 format in UTC) |
| `reporting_periods` | array | List of reporting period IDs contained in this employer check |
# Get Employer Check by ID
Source: https://docs.zeal.com/reference/employer-checks/get-employer-check-by-id
openapi/zeal-api.json get /employerCheck
Retrieve employer check records for a company by companyID.
# Create Garnishment
Source: https://docs.zeal.com/reference/garnishments/create-garnishment
openapi/zeal-api.json post /garnishments
Creates a garnishment for an employee or contractor.
Creates a garnishment for an employee or contractor. Provide either simple caps (`cap_amount` and/or `cap_percentage`) **or** an advanced `withholding_schedule` (not both). Advanced schedules are employee-only — contractors have no pay frequency, so use simple caps instead. When both caps are set, the withholding engine applies the stricter (lower) of the two on each check or payment. A schedule defines fixed amounts and/or disposable-earnings brackets per pay frequency (money fields in dollars). Each frequency branch must tile disposable earnings from `$0.00` to infinity with no gaps or overlaps (first `min` is `0`, each next `min` is the previous `max` plus `$0.01`, last `max` is `null`), and at least one bracket must withhold. A schedule does not need to cover every pay frequency — include only the frequencies the order specifies; a payment whose pay frequency is not listed in the schedule withholds nothing. You may pass `total_amount_withheld` to seed prior withholdings (for example when migrating an existing order); when `total_amount_owed` is set, it must be greater than or equal to `total_amount_withheld`.
# Garnishment Object
Source: https://docs.zeal.com/reference/garnishments/garnishment-object
The Garnishment Object represents a court or agency withholding order applied to an employee or contractor.
The Garnishment Object represents a court or agency withholding order applied to an employee or contractor. Amounts are returned in dollars.
| attribute | type | description |
| :----------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `garnishmentID` | string | Unique identifier for this garnishment |
| `companyID` | string | Company ID of employer |
| `workerID` | string | Employee or contractor ID this garnishment applies to |
| `workerType` | string | `employee` or `contractor`. Advanced `withholding_schedule` is employee-only |
| `garnishment_type` | string | One of `child_support`, `federal_tax_levy`, `state_tax_levy`, `creditor`, `student_loan`, `other` |
| `priority` | integer | Effective withholding priority. Lower numbers are withheld first. When omitted on create, Zeal applies a type-based default: `child_support`=10, `federal_tax_levy`=20, `state_tax_levy`=30, `student_loan`=40, `creditor`=50, `other`=60 |
| `total_amount_owed` | number | Total balance owed in dollars. Omitted for open-ended orders |
| `total_amount_withheld` | number | Total amount withheld to date in dollars |
| `status` | string | One of `active`, `satisfied`, `modified`, `vacated`, `canceled` |
| `effective_start_date` | string | ISO date (`YYYY-MM-DD`) when withholding begins |
| `effective_end_date` | string | ISO date (`YYYY-MM-DD`) when withholding ends. Omitted for open-ended orders |
| `agency_name` | string | Name of the collecting agency |
| `agency_address` | string | Address of the collecting agency |
| `cap_amount` | number | Per-paycheck maximum withhold amount in dollars. Mutually exclusive with `withholding_schedule` |
| `cap_percentage` | number | Per-paycheck maximum withhold percentage of disposable earnings (`0`-`100`). Mutually exclusive with `withholding_schedule` |
| `withholding_schedule` | array | Advanced per-pay-frequency schedule (fixed amounts and/or disposable-earnings brackets). Employee-only — contractors have no pay frequency, so use `cap_amount` / `cap_percentage` instead. Mutually exclusive with `cap_amount` / `cap_percentage`. Money fields in dollars. On create or when sent on update, each frequency must tile `$0.00` to infinity with no gaps or overlaps, and at least one bracket must withhold. A schedule does not need to cover every pay frequency — a payment whose frequency is not listed withholds nothing. On update, sending a non-null schedule (or a non-null simple cap) clears the omitted opposite mode. See schema on Create / Update. |
| `garnishment_state` | string | US state code (2-letter) associated with the order |
| `case_id` | string | Court/agency case identifier |
| `order_number` | string | Court/agency order number |
| `custom_name` | string | Optional display name for this garnishment |
| `external_id` | string | Optional external identifier for your own systems |
| `previous_garnishmentID` | string | ID of the garnishment this record supersedes. Present when this garnishment was created via a modify (`status: "modified"`) transition; omitted otherwise |
| `canceled_reason` | string | Reason provided when status is `canceled` |
| `satisfied_at` | string | ISO timestamp when the garnishment was fully satisfied |
| `created_at` | string | ISO timestamp when the garnishment was created |
| `updated_at` | string | ISO timestamp when the garnishment was last updated |
Simple caps (`cap_amount` / `cap_percentage`):
```json theme={null}
{
"garnishmentID": "3cab1c18d38a45e7a688aceeb4fcfcaa",
"companyID": "1eeec343485723ee58afef12",
"workerID": "674759a85785745748e3847a",
"workerType": "contractor",
"garnishment_type": "creditor",
"priority": 50,
"total_amount_owed": 500,
"total_amount_withheld": 0,
"status": "active",
"effective_start_date": "2025-01-01",
"agency_name": "Acme Agency",
"agency_address": "123 Court St",
"cap_percentage": 25,
"case_id": "CASE-1",
"order_number": "ORD-1",
"created_at": "2025-01-01T00:00:00.000Z",
"updated_at": "2025-01-01T00:00:00.000Z"
}
```
Withholding schedule (advanced withholding; employees only). Weekly uses disposable-earnings brackets; monthly uses a fixed amount. A payment whose pay frequency is not listed withholds nothing:
```json theme={null}
{
"garnishmentID": "3cab1c18d38a45e7a688aceeb4fcfcaa",
"companyID": "1eeec343485723ee58afef12",
"workerID": "674759a85785745748e3847a",
"workerType": "employee",
"garnishment_type": "creditor",
"priority": 50,
"total_amount_owed": 500,
"total_amount_withheld": 0,
"status": "active",
"effective_start_date": "2025-01-01",
"agency_name": "Acme Agency",
"agency_address": "123 Court St",
"withholding_schedule": [
{
"frequency": "weekly",
"brackets": [
{ "min": 0, "max": 217.5, "action": { "kind": "exempt" } },
{
"min": 217.51,
"max": 290,
"action": { "kind": "excess_over_floor", "floor": 217.5 }
},
{
"min": 290.01,
"max": null,
"action": { "kind": "percentage", "percentage": 25 }
}
]
},
{
"frequency": "monthly",
"brackets": [
{ "min": 0, "max": null, "action": { "kind": "amount", "amount": 937.5 } }
]
}
],
"case_id": "CASE-1",
"order_number": "ORD-1",
"created_at": "2025-01-01T00:00:00.000Z",
"updated_at": "2025-01-01T00:00:00.000Z"
}
```
# Get Garnishment
Source: https://docs.zeal.com/reference/garnishments/get-garnishment
openapi/zeal-api.json get /garnishments/{garnishmentID}
Fetch a single garnishment by ID.
# Get Garnishments
Source: https://docs.zeal.com/reference/garnishments/list-garnishments
openapi/zeal-api.json get /garnishments
Returns a cursor-paginated list of garnishments for a company.
Returns a cursor-paginated list of garnishments. Use `start_at` from `meta.next` / `meta.previous` to page. `workerID` and `workerType` must be provided together when filtering by worker.
# Update Garnishment
Source: https://docs.zeal.com/reference/garnishments/update-garnishment
openapi/zeal-api.json patch /garnishments/{garnishmentID}
Transitions a garnishment lifecycle status: modify (supersede), cancel, or vacate.
Garnishment details are append-only. Every `PATCH` is a lifecycle transition keyed on `status`. Only `active` garnishments can be updated.
### Modify (`status: "modified"`)
Supersedes the existing record with a new linked garnishment. This is the only way to change withholding terms or display fields. Send a partial `modification` object — omitted fields are inherited from the superseded record. Optional fields accept `null` to clear them on the replacement. Simple caps (`cap_amount` / `cap_percentage`) and `withholding_schedule` are mutually exclusive: sending a non-null value on one mode clears the omitted opposite mode, so a mode switch does not need to null the other side. Sending both modes together is rejected. When you send a `withholding_schedule`, the garnishment must be for an employee (contractors have no pay frequency; use simple caps instead). The schedule must tile `$0.00` to infinity per pay frequency with no gaps or overlaps, and at least one bracket must withhold. It does not need to cover every pay frequency — include only the frequencies the order specifies; a payment whose pay frequency is not listed withholds nothing. The resulting record must still have at least one withholding rule. The response is the **new** active garnishment with `previous_garnishmentID` set to the superseded record's ID; amount already withheld is carried forward.
### Cancel (`status: "canceled"`)
Closes the garnishment in place. Requires `canceled_reason` (for mistakes, duplicates, bad worker match, or other non-legal cancellation).
### Vacate (`status: "vacated"`)
Closes the garnishment in place when the court/order was withdrawn or overturned.
# Authentication and Keys
Source: https://docs.zeal.com/reference/introduction/authentication-and-keys
Learn how to obtain your Zeal API keys, pass them as Bearer tokens, manage test vs. production keys, and keep your credentials secure.
Every request to the Zeal REST API must be authenticated with an API key issued to your partner account. Zeal uses standard HTTP Bearer token authentication - you include your key in the `Authorization` header of every request. There are no session tokens or cookie-based flows; each request is independently authenticated.
## Obtaining your API keys
Your API keys live on the **API** page of the Partner Dashboard at [app.zeal.com](https://app.zeal.com). You will find both a **Test API key** and a **Production API key** there, along with your **`partnerID`**.
If you are logging in for the first time, click **Forgot Password** on the login screen to set your password. Once inside the dashboard, navigate to the **API** page and copy the key appropriate for your environment.
## Passing the API key
Include the key in the `Authorization` header of every HTTP request:
```
Authorization: Bearer {apiKey}
```
Replace `{apiKey}` with your actual key. The header must appear on every request - there is no session-level authentication.
### Example request
```bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/companies?partnerID=YOUR_PARTNER_ID' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY'
```
## Test vs. production keys
Zeal maintains two fully isolated environments. Each has its own API key.
| Key type | Environment | Effect |
| ---------------------- | -------------- | ------------------------------------------------------------------------------------------ |
| **Test API key** | Test (sandbox) | Payroll is processed end-to-end but **no money is moved** and no real tax filings are made |
| **Production API key** | Production | Payroll runs for real - money is disbursed, taxes are filed |
Use your **Test API key** for all development and integration work. Resources created with the Test key (companies, workers, checks) are completely isolated from Production and will not appear in the live environment.
## The partnerID header
Some endpoints require a `partnerID` in addition to your API key. The `partnerID` identifies your Zeal partner account and is found on the same **API** page as your keys. It is typically passed as a request body parameter (for `POST`/`PATCH` requests) or as a query parameter (for `GET` requests) rather than as a header.
## Rolling a compromised key
If you believe a key has been exposed, rotate it immediately from the **API** page of the Partner Dashboard. Click the **refresh icon** next to the compromised key and follow the on-screen prompts. The old key is invalidated instantly and a new key is issued. Update any systems that relied on the old key before the rotation.
Never commit API keys to version control, include them in client-side code, or log them to any output stream. Treat them with the same care you would a password. Grant access only to team members and services that genuinely need it.
## Webhook authentication
When Zeal sends webhook payloads to your configured endpoints, it includes a `Puzzl-Signature` header containing a shared secret. You can find this secret under the **Webhook secrets** tab on the **API** page. Configure your webhook handlers to reject any request that does not include a valid `Puzzl-Signature` header to prevent spoofed events.
# Early Access Endpoints
Source: https://docs.zeal.com/reference/introduction/early-access-endpoints
If endpoints are marked Early Access, they are available on a case-by-case basis per partner contracts.
If endpoints are marked Early Access, they are available on a case-by-case basis per partner contracts. Please contact the Zeal team to enable these features.
# Error Codes
Source: https://docs.zeal.com/reference/introduction/error-codes
HTTP status codes and error codes returned by the Zeal API, with their meanings.
All of Zeal's responses follow HTTP Status Codes.
| HTTP Status | Meaning |
| ---------------------------------- | ----------------------------------------------------------------------------------------------- |
| 200 - OK | Everything worked as expected |
| 400 - Bad Request | The request was unacceptable, often due to a missing or incorrect required parameter |
| 401 - Unauthorized | No valid API Key provided |
| 402 - Request Failed | The parameters were valid but the request failed |
| 403 - Forbidden | The API key doesn't have permission to perform the request |
| 404 - Not Found | The requested resource doesn't exist |
| 409 - Conflict | The request conflicts with another request |
| 429 - Too Many Requests | Too many requests hit the API too quickly. We recommend an exponential backoff of your requests |
| 500, 502, 503, 504 - Server Errors | Something went wrong on Zeal's end |
Zeal API error messages are returned in JSON format.
```json theme={null}
{
"success": false,
"errors": [
{
"message": "Employee does not exist",
"code": 30
}
]
}
```
| Error Code | Message | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| 0 | This account does not have access to live payroll. You may only use Test Keys/Test Mode for now | Corresponds with HTTP 403The account does not have access to live payroll yet. Please contact Zeal support to gain access. |
| 1 | No Authorization Header | Corresponds with HTTP 400No authorization header or Bearer Token was found in the request |
| 2 | No companyID in the request query | Corresponds with HTTP 400No companyID was found in the query of request when expected. |
| 3 | No companyID in the request body | Corresponds with HTTP 400No companyID was found in the body of the request when expected. |
| 4 | No user with this companyID exists | Corresponds with HTTP 400No user with the given companyID exists. |
| 6 | No partnerID in the body or query of request | Corresponds with HTTP 400No partnerID was found in the body or query of the request when expected |
| 7 | No Zeal Partner with this partnerID exists | Corresponds with HTTP 400No Zeal Partner with the given partner ID exists. |
| 8 | Error with Key | Corresponds with HTTP 401Given API key does not exist for Zeal partner with given partnerID |
| 9 | Invalid format for the time given in the query | Corresponds with HTTP 400The format of the time parameter for the request does not adhere to the ISO-8601 format. |
| 10 | Reporting Period with this ID does not exist | Corresponds with HTTP 400No Reporting Period with this ID exists. |
| 11 | No 'shifts' array found in the body of the request | Corresponds with HTTP 400 |
| 12 | Worker(s) with given employeeID(s) in the body of the request does not exist | Corresponds with HTTP 400 |
| 13 | Object(s) is missing required fields or have improperly formatted data | Corresponds with HTTP 400. Consult API reference for proper formatting. |
| 14 | Shift(s) with given shiftID(s) is not found for this user | Corresponds with HTTP 404This could have occurred because of an improperly formatted shiftID. |
| 16 | No employeeCheckID found in the query of the request | Corresponds with HTTP 400 |
| 17 | Object with this ID does not exist | Corresponds with HTTP 400 |
| 18 | No end date found in the query of the request | Corresponds with HTTP 400 |
| 19 | No start date found in the query of the request | Corresponds with HTTP 400 |
| 20 | Dates provided in the query of request are invalid/inappropriately formatted | Corresponds with HTTP 400. Please format dates as YYYY-MM-DD |
| 21 | End Date occurs before Start Date | Corresponds with HTTP 400 |
| 22 | No 'employees' array found in the body of the request | Corresponds with HTTP 400 |
| 23 | Employee with this employeeID does not exist | Corresponds with HTTP 400 |
| 24 | Zeal Partner does not have access to this company's information | Corresponds with HTTP 400 |
| 25 | This is only a Live Mode feature. Test Key does not have permission to perform this request | Corresponds with HTTP 403. |
| 26 | No shiftID in the query of request | Corresponds with HTTP 400 |
| 27 | No 'new\_employees' array found in the body of the request | Corresponds with HTTP 400 |
| 28 | Employee object(s) are missing the required fields. | Corresponds with HTTP 400 |
| 29 | Worker(s) with given email(s) already exist. Please try again | Corresponds with HTTP 404 |
| 30 | Employee is already onboarded/on leave/terminated | Corresponds with HTTP 404 |
| 31 | No Pending Employee Check exists within the given employeeCheckID | Corresponds with HTTP 404 |
| 32 | Employee Check for this employee and check date already exists. Error object will include an employeeID and check date | Corresponds with HTTP 400 |
| 33 | This employee is working in a state for which a State Payroll Tax Number has not been submitted. This error only applies in Live Mode | Corresponds with HTTP 400 |
| 34 | The address provided is not suitable for taxation. Address fields where wholly invalid or resolved to a taxable location with *is\_suitable\_for\_taxation* equal to **false**. Use the [Resolve Taxable Location](/reference/taxable-locations/resolve-taxable-location) endpoint for more details | Corresponds with HTTP 400 |
| 35 | No contractorID in the body/query of the request | Corresponds with HTTP 400 |
| 36 | Object(s) does not have a bank account | Corresponds with HTTP 400 |
| 37 | Cannot onboard employee: missing property | Corresponds with HTTP 400 |
| 38 | Employee is already onboarded | Corresponds with HTTP 400 |
| 39 | Internal Server Error | Corresponds with 500. Message will relay actual server error. |
| 40 | CompanyID mismatch in body and query of request | Corresponds with HTTP 400 |
| 41 | Key is not authorized to perform this request | Corresponds with HTTP 403 |
| 42 | No contractorID or employeeID in the body/query of the request | Corresponds with HTTP 400 |
| 43 | Employee Check with this check ID does not exist | Corresponds with HTTP 400 |
| 44 | Date is not a valid date | Corresponds with HTTP 400 |
| 45 | Date must not be in the past | Corresponds with HTTP 400 |
| 46 | Contractor Payment with this payment ID does not exist | Contractor Payment with this payment ID does not exist |
| 47 | Validation Error | Corresponds with HTTP 403 |
| 48 | The address provided is not a valid, mail-deliverable address | Corresponds with HTTP 400 |
| 49 | Company must be live | Corresponds with HTTP 403 |
| 50 | Must provide a valid companyID | Corresponds with HTTP 400 |
| 51 | No company with this companyID exists | Corresponds with HTTP 404 |
| 52 | No document with this document ID exists | Corresponds with HTTP 404 |
| 53 | No document of this type within the given scope exists | Corresponds with HTTP 404 |
| 54 | No document with this jurisdiction and company ID has been submitted | Corresponds with HTTP 404 |
| 55 | Shifts with negative wages not currently supported | Corresponds with HTTP 400 |
| 56 | Routing number is invalid | Corresponds with HTTP 400 |
| 57 | Employee or contractor has not finished onboarding | Corresponds with HTTP 400 |
| 58 | Work Location(s) not found | Corresponds with HTTP 400 |
| 59 | Failed to update/upsert Work Location | Corresponds with HTTP 400 |
| 60 | Failed to create Work Location | Corresponds with HTTP 400 |
| 61 | Another employee in this company already has the same SSN | Corresponds with HTTP 400 |
| 62 | Create employees payload contains duplicate SSNs | Corresponds with HTTP 400 |
| 63 | SSN must be an optional property or of type string | Corresponds with HTTP 400 |
| 64 | Request is not of the expected shape | Corresponds with HTTP 400 |
| 65 | Maximum number of allowed checks exceeded | Corresponds with HTTP 400 |
| 66 | Only pending checks can be previewed. Received non-pending check(s) | Corresponds with HTTP 400 |
| 67 | No workLocationID in the body of the request | Corresponds with HTTP 400 |
| 68 | Bank Account with this employeeID or contractorID does not exist | Corresponds with HTTP 400 |
| 69 | Another employee in this company already has the same external ID | Corresponds with HTTP 400 |
| 70 | Another contractor in this company already has the same external ID | Corresponds with HTTP 400 |
| 71 | No W-4 exists for this jurisdiction | Corresponds with HTTP 400 |
| 72 | Employee or Contractor ID is not formatted correctly | Corresponds with HTTP 400 |
| 73 | Contractor with this contractorID does not exist | Corresponds with HTTP 400 |
| 74 | Invalid check date | Corresponds with HTTP 400 |
| 75 | Must be valid SSN format - eg. XXXYYZZZZ | Corresponds with HTTP 400 |
| 76 | Another contractor in this company already has the same SSN | Corresponds with HTTP 409 |
| 77 | Start date cannot be after end date | Corresponds with HTTP 400 |
| 78 | Email already exists | Corresponds with HTTP 409 |
| 79 | Migration failed | Corresponds with HTTP 400 |
| 80 | Please provide a file to upload | Corresponds with HTTP 400 |
| 81 | Contractor Payment for this contractor and pay date already exists. Error object will include a contractorID and pay\_date | Corresponds with HTTP 400 |
| 82 | CompanyID was not found | Corresponds with HTTP 400 |
| 83 | Failed to retrieve Partner Information by ID | Corresponds with HTTP 400 |
| 84 | Email or password is incorrect | Corresponds with HTTP 401 |
| 85 | Partner not found | Corresponds with HTTP 400 |
| 86 | Either document ID or type, jurisdiction, and scope are required | Corresponds with HTTP 400 |
| 87 | Employee has missing or invalid residency | Corresponds with HTTP 422 |
| 88 | Contractor is already onboarded | Corresponds with HTTP 400 |
| 89 | The given date is on a weekend/bank holiday or the current time is after 2 PM two days before the given date. Please correct the date and resubmit | Corresponds with HTTP 400 |
| 90 | Only able to regenerate requirement for state-scoped requirements | Corresponds with HTTP 400 |
| 91 | Invalid tax parameter jurisdiction | Corresponds with HTTP 400 |
| 92 | Invalid tax requirement ID | Corresponds with HTTP 400 |
| 93 | Invalid tax parameter value | Corresponds with HTTP 400 |
| 94 | Employee's default wage has not been set so please provide an appropriate wage in the shifts object(s) | Corresponds with HTTP 400 |
| 95 | The requested feature is disabled | Corresponds with HTTP 403 |
| 96 | Value must be positive | Corresponds with HTTP 400 |
| 97 | Email must be valid | Corresponds with HTTP 400 |
| 98 | This account does not have access to this endpoint | Corresponds with HTTP 403 |
| 99 | This employee is not onboarded | Corresponds with HTTP 400 |
| 100 | This employee is on leave/terminated | Corresponds with HTTP 400 |
| 101 | Forbidden | Corresponds with HTTP 403 |
| 102 | You must create between 1 and 100 checks | Corresponds with HTTP 400 |
| 103 | Unauthorized | Corresponds with HTTP 401 |
| 104 | Provided deduction template id(s) not found under companyID | Corresponds with HTTP 404 |
| 105 | Parameter is expected to be of type objectid string | Corresponds with HTTP 400 |
| 106 | Net pay negative - this check will fail | Corresponds with HTTP 422 |
| 107 | Bad Form Data | Corresponds with HTTP 422 |
| 108 | Provided check is invalid | Corresponds with HTTP 400 |
| 109 | Accrual policy with this policy code not found | Corresponds with HTTP 404 |
| 110 | Historical shift would be modified by overtime calculation | Corresponds with HTTP 422 |
| 111 | Value for earning type must be less than 0 | Corresponds with HTTP 400 |
| 112 | Value must be negative | Corresponds with HTTP 400 |
| 113 | Jurisdiction does not exist | Corresponds with HTTP 404 |
| 114 | Company not setup for regular payroll | Corresponds with HTTP 400 |
| 115 | Account not found | Corresponds with HTTP 404 |
| 116 | Value must be a decimal | Corresponds with HTTP 400 |
# Idempotency
Source: https://docs.zeal.com/reference/introduction/idempotency
You can add an Idempotency Key in the request headers to ensure that a particular operation is only performed once.
You can add an Idempotency Key in the request headers (`x-idempotency-key`) to ensure that a particular operation is only performed once, regardless of how many times the request is made for 24 hours since the original request. It is used by the backend to identify duplicate requests, preventing the execution of the same operation multiple times. This is useful for operations such as payments or submissions to avoid duplicate processing.
This applies to both Test and Production modes.
# Introduction
Source: https://docs.zeal.com/reference/introduction/introduction
Explore the Zeal REST API: base URL, authentication, request and response formats, environments, and available resource groups for embedded payroll.
The Zeal REST API gives you programmatic access to every aspect of embedded payroll - from creating companies and onboarding workers to running payroll and filing taxes. All requests go to a single base URL, use JSON for both request bodies and response payloads, and are authenticated with a Bearer token tied to your Zeal partner account.
## Base URL
Every API request is sent to:
```
https://api.zeal.com
```
There is no version prefix in the path. All current endpoints are available directly beneath this root (for example, `https://api.zeal.com/companies`).
## Request and response format
All request bodies must be sent as JSON with the `Content-Type: application/json` header. All successful responses are returned as JSON. Dates follow ISO 8601 (`YYYY-MM-DD`) unless otherwise noted in a specific endpoint's documentation.
## Authentication
Every request must include an `Authorization` header with a Bearer token equal to your API key:
```
Authorization: Bearer {apiKey}
```
Your API keys are available on the **API** page of your Partner Dashboard at [app.zeal.com](https://app.zeal.com). See the [Authentication](/reference/introduction/authentication-and-keys) page for full details.
## Example request
The snippet below shows a minimal authenticated request that lists all companies under your partner account.
```bash theme={null}
curl --request GET \
--url 'https://api.zeal.com/companies?partnerID=YOUR_PARTNER_ID' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY'
```
## Environments
Zeal provides two isolated environments, each with its own set of API keys.
| Environment | Purpose | Money movement |
| -------------- | ----------------------------------- | -------------------------- |
| **Test** | Development and integration testing | No real money is disbursed |
| **Production** | Live payroll operations | Real money is disbursed |
Use your **Test API key** for all development and QA work. Switch to your **Production API key** only when you are ready to process real payroll. Test and Production resources are completely separate - data created in one environment does not appear in the other.
## Partner ID vs Company ID
Two identifiers appear frequently across the API:
* **`partnerID`** - Identifies your Zeal partner account. Use this when creating companies or fetching resources that are scoped to your entire partner account. You can find your `partnerID` on the **API** page of the Partner Dashboard.
* **`companyID`** - Identifies a specific employer company under your partner account. Most company-level and worker-level endpoints require a `companyID`. It is returned when you call `POST /companies` and is also visible in the Partner Dashboard.
## Error format
When a request fails, Zeal returns a non-2xx HTTP status code and a JSON body describing the problem. Errors follow the standard response envelope: `success` is `false` and `errors` is an array of error objects, each with a `message` and a `code` (see [Error Codes](/reference/introduction/error-codes)):
```json theme={null}
{
"success": false,
"errors": [
{
"message": "Description of what went wrong",
"code": 13
}
]
}
```
Common status codes:
| Status | Meaning |
| ------ | ------------------------------------------------- |
| `200` | Success |
| `400` | Bad request - check your request parameters |
| `401` | Unauthorized - invalid or missing API key |
| `404` | Not found - the requested resource does not exist |
| `429` | Too many requests - you have been rate-limited |
| `500` | Internal server error - contact Zeal support |
## Resource groups
The API reference is organized into resource groups - Companies, Employees, Contractors, Employee Checks, Contractor Payments, Reports, Webhooks, and more. Browse the sidebar to explore each group and its endpoints.
# Metadata
Source: https://docs.zeal.com/reference/introduction/metadata
Updateable objects in Zeal, such as Employee Check, Shifts, and Payment Items, have a metadata parameter you can use to attach key-value data to Zeal objects.
Updateable objects in Zeal, such as Employee Check, Shifts, and Payment Items, have a metadata parameter. You can use this parameter to attach key-value data to Zeal objects. Metadata is useful for storing additional, structured information on an object.
For instance, you could store your descriptions of jobs in the metadata object of a Zeal Shift object or use the metadata object for correlation IDs so you can parse the response from Zeal.
Metadata is not used in any way by Zeal - you may use the metadata object in any way you like. However, please do not store any sensitive information as metadata.
The metadata object can take any JSON type.
```json EXAMPLE METADATA OBJECT theme={null}
{
"metadata": {
"jobID": "19834673",
"description": "Piecework pay"
}
}
```
# Pagination
Source: https://docs.zeal.com/reference/introduction/pagination
Zeal's API endpoints use cursor-based pagination through the start_at parameter.
Zeal's API endpoints use cursor-based pagination through the `start_at` parameter. `start_at` accepts an existing object ID value and returns a limited set of objects in chronological order. The `start_at` parameter returns objects listed at and after the named object.
Not all Zeal API endpoints allow pagination. You can see whether an endpoint employs pagination or not by visiting the endpoint's documentation.
Example:
```curl JSON theme={null}
curl --request GET \
--url https://api.zeal.com/company/2d37ce1146d275fa36b108c54a7c02e8/contractorPayments?start_at=d210f054bf5b006f50aecbd7&limit=10 \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{testApiKey}}'
```
```json JSON theme={null}
{
"data": [...],
"success": true,
"testMode": true,
"meta": {
"next": "https://api.zeal.com/company/2d37ce1146d275fa36b108c54a7c02e8/contractorPayments?start_at=d210f054bf5b006f50aecbe1&limit=10",
"previous": null
}
}
```
# Rate Limiting
Source: https://docs.zeal.com/reference/introduction/rate-limiting
The Zeal API employs rate limiting to help maximize its stability.
The Zeal API employs rate limiting to help maximize its stability.
Our rate limiter limits the number of requests to 100 requests to the API per second.\
Users who send more than 100 requests in a given second will get an error response with status code *429*.\
This applies to both Test and Production modes.
# Times and Dates
Source: https://docs.zeal.com/reference/introduction/times-and-dates
All times and dates required for Zeal's Payroll API should ideally be represented as date-times or dates in ISO-8601 format in UTC.
All times and dates required for Zeal's Payroll API should ideally be represented as date-times or dates in ISO-8601 format in UTC: YYYY-MM-DDTHH:MM:SSZ (e.g, `2024-04-16T19:21:51Z`,`2024-04-16`).
# Create a paperwork submission
Source: https://docs.zeal.com/reference/paperwork-api/create-paperwork-submission
openapi/zeal-api.json put /paperwork/submissions
Create a Paperwork Submission for an employee or contractor from a Paperwork Template.
Create a Paperwork Submission(s). This endpoint will return the created Paperwork Submission object(s).
# Get paperwork submissions
Source: https://docs.zeal.com/reference/paperwork-api/get-paperwork-submissions
openapi/zeal-api.json post /paperwork/submissions
Get one or more Paperwork Submissions by company ID or filters.
Gets one or more Paperwork Submission(s) by companyID or various filters. This endpoint will return an array of Paperwork Submission object(s).
# Get Paperwork Template by ID
Source: https://docs.zeal.com/reference/paperwork-api/get-paperwork-template-by-id
openapi/zeal-api.json get /paperwork/templates/{templateID}
Fetch a specified Paperwork Template by its template ID.
Fetches a specified Paperwork Template by `templateID`. This endpoint will return the fetched [Paperwork Template](/reference/paperwork-api/paperwork-template-object) object.
# Get Paperwork Templates
Source: https://docs.zeal.com/reference/paperwork-api/get-paperwork-templates
openapi/zeal-api.json post /paperwork/templates
Get one or more Paperwork Templates by company ID or filters.
Gets one or more Paperwork Template(s) by companyID or various filters. This endpoint will return an array of [Paperwork Template](/reference/paperwork-api/paperwork-template-object) object(s).
# Get a specific paperwork submission
Source: https://docs.zeal.com/reference/paperwork-api/get-specific-paperwork-submission
openapi/zeal-api.json get /paperwork/submissions/{submissionID}
Gets a specific Paperwork Submission(s) by its submissionID.
Gets a specific Paperwork Submission(s) by its `submissionID`. This endpoint will return an array of Paperwork Submission object(s).
# Paperwork Submission Object
Source: https://docs.zeal.com/reference/paperwork-api/paperwork-submission-object
The Paperwork Submission object represents a submitted paperwork form for a worker's onboarding process.
The Paperwork Submission object represents a submitted paperwork form for a worker's onboarding process.
| attribute | type | description |
| :--------------- | :----- | :--------------------------------------------------------------------- |
| templateID | string | Unique identifier for the template used for this submission |
| submissionID | string | Unique identifier for the submission |
| submission\_date | string | Date and time when the paperwork was submitted (format: ISO 8601) |
| worker\_type | string | Type of worker. Can be `employee` or `contractor` |
| companyID | string | Unique identifier for Zeal company |
| employeeID | string | Unique identifier for the employee (if worker\_type is 'employee') |
| contractorID | string | Unique identifier for the contractor (if worker\_type is 'contractor') |
| fields | object | Key-value pairs of submitted form fields |
| jurisdiction | string | Abbreviation of jurisdiction |
| paperwork\_type | string | Type of paperwork form submitted (W4 or I9) |
| url | string | URL to access the submitted paperwork |
## Example Paperwork Submission Object
```json theme={null}
{
"templateID": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"submissionID": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"submission_date": "2023-06-01T12:00:00Z",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"contractorID": null,
"jurisdiction": "VA",
"fields": {
"field1": "value1",
"field2": "value2"
},
"paperwork_type": "W4",
"url": "https://example.com/submission/12345"
}
```
# Paperwork Template Object
Source: https://docs.zeal.com/reference/paperwork-api/paperwork-template-object
The Paperwork Template object represents a template for custom paperwork used during a worker's onboarding process.
# Paperwork Template Object
The Paperwork Template object represents a template for custom paperwork that can be utilized during a worker's onboarding process.
| attribute | type | description |
| --------------------- | ------ | ---------------------------------------------------------------------------------------------- |
| templateID | string | Unique identifier for the template |
| companyID | string | Unique identifier for Zeal company |
| form\_name | string | Name of the paperwork form |
| description | string | Description of the paperwork form |
| paperwork\_type | string | Type of paperwork form. Holds one of the following values: `W4`, `I9`, `W9`, `CustomPaperwork` |
| worker\_type | string | Type of worker the form is applicable to. Can be `Employee`, `Contractor`, or `All` |
| jurisdictions\_filter | object | Filter for jurisdictions where the form is applicable |
| jurisdiction\_type | string | Type of jurisdiction for the form. Can be `WorkLocation`, `Residency`, or `All` |
| effective\_date | string | Date from which the template is effective (format: YYYY-MM-DD) |
| archive\_date | string | Date when the template will be archived (format: YYYY-MM-DD) |
| form\_fields | array | Array of form fields in the template |
| urls | array | List of URLs associated with the template |
| status | string | Current status of the template. Can be `Draft`, `Live`, or `Archived` |
## Example Paperwork Template Object
```bash bash theme={null}
{
"templateID": "template_123456",
"companyID": "fc235fcccee46aa8a082f357715bcfa",
"form_name": "Updated W-4 Form",
"description": "Updated Employee's Withholding Certificate",
"paperwork_type": "W4",
"worker_type": "Employee",
"jurisdictions_filter": {
"type": "include",
"jurisdictions": [
"CA",
"NY",
"TX"
]
},
"jurisdiction_type": "WorkLocation",
"effective_date": "2023-08-01",
"archive_date": "2024-07-31",
"form_fields": [
{
"field_name": "employee_name",
"label": "Employee's Full Name",
"type": "string",
"required": true
},
{
"field_name": "ssn",
"label": "Social Security Number",
"type": "string",
"required": true
}
],
"urls": [
"https://example.com/updated_w4_form.pdf"
],
"status": "Live"
}
```
# Get Paycards
Source: https://docs.zeal.com/reference/paycards/get-paycards
openapi/zeal-api.json get /paycards
Retrieve paycards for a company, optionally filtered by employee, contractor, paycard ID, or date range.
# Paycard Object
Source: https://docs.zeal.com/reference/paycards/paycard-object
Attributes of the Paycard object, including status and type values.
| attribute | type | description |
| ------------ | ------ | ----------------------------------------------------------------- |
| paycardID | string | Zeal Paycard ID |
| companyID | string | Zeal Company ID |
| employeeID | string | Zeal Employee ID |
| contractorID | string | Zeal Contractor ID |
| status | string | Holds one of the following values:`active``suspended``terminated` |
| type | string | Holds one of the following values:`virtual``physical` |
```bash bash theme={null}
{
"paycardID": "f15b00a4bce0e60d52bf0f0a",
"companyID": "bf015b00e052f60cfb0e4a0d",
"employeeID": "d210f054bf5b006f50aecbe0",
"contractorID": null,
"status": "active",
"card_type": "virtual",
}
```
# Create Payment Item
Source: https://docs.zeal.com/reference/payment-items/create-payment-item
openapi/zeal-api.json post /payment-items
Add a payment item line to a pending contractor payment.
Creates a new [Payment Item](/reference/payment-items/payment-item-object) and adds it to a contractor payment. Payment items can only be added to a contractor payment with the status pending.
# Delete Payment Item
Source: https://docs.zeal.com/reference/payment-items/delete-payment-item
openapi/zeal-api.json delete /payment-items
Delete a payment item by paymentItemID from a pending contractor payment.
Deletes an existing [Payment Item](/reference/payment-items/payment-item-object). Payment items can only be deleted when the parent contractor payment has status pending.
# Get Payment Items
Source: https://docs.zeal.com/reference/payment-items/get-payment-items
openapi/zeal-api.json get /payment-items
Retrieve a payment item by paymentItemID, or list payment items for a company, optionally filtered by contractor, contractor payment, or service type.
This endpoint serves two usages on the same path. Pass `paymentItemID` to retrieve a single [Payment Item](/reference/payment-items/payment-item-object). Omit `paymentItemID` to list payment items; you can optionally pass `contractorID`, `contractorPaymentID`, or `serviceTypeID` to filter that list.
When `paymentItemID` is present, list filters (`contractorID`, `contractorPaymentID`, `serviceTypeID`) and pagination parameters are ignored.
Listing responses include `meta` with `next`, `previous`, and `totalCount`.
# Payment Item Object
Source: https://docs.zeal.com/reference/payment-items/payment-item-object
Individual line items within a contractor payment, referencing a service type or standalone.
Payment items represent individual line items within a contractor payment. They can reference a service type or be standalone. Payment items can only be added to contractor payment with the status pending.
| attribute | type | description |
| ------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| paymentItemID | string | Unique identifier representing this payment item. |
| companyID | string | Company ID that this customer account is under. |
| contractorID | string | ID of contractor. |
| contractorPaymentID | string | ID contractor payment that this payment item is associated with. |
| work\_info | object | Contains: `work_description`: Custom description of payment item (string); `service_date`: Datetime of service completed (string). |
| earning\_type | string | Can be one of the following: `hourly`, `per_unit`, `flat_fee`, `expense_reimbursement`, `bonus`. |
| rate | float | **Only required if `earning_type` is `hourly` or `per_unit`**. |
| rate\_unit | float | **Only required if `earning_type` is `hourly` or `per_unit`**. Can be one of the following: `hour`, `project`, `piece`. |
| quantity | float | **Only required if `earning_type` is `hourly` or `per_unit`**. |
| bill\_rate | float | **Only applicable if `earning_type` is `hourly` or `per_unit`**. |
| gross\_amount | float | **Only required if `earning_type` is `flat_fee`, `expense_reimbursement`, or `bonus`**. |
| bill\_amount | float | **Only applicable if `earning_type` is `flat_fee`, `expense_reimbursement`, or `bonus`**. |
| metadata | object | Custom object you can attach to the payment item. Useful for storing additional information in a custom, structured format. Zeal does not use this object. Do not store sensitive information. Posting `metadata` replaces the whole object. See [Metadata](/reference/introduction/metadata). |
```json JSON theme={null}
{
"paymentItemID": "a3f9c2d1e6b74a8f9c3d2b1e7f8a9c01",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"contractorID": "669fe6216d9eff8ca4c9f0de",
"contractorPaymentID": "68ffb95239326ca8713eadb1",
"work_info": {
"work_description": "Bartending service",
"service_date": "2026-03-20"
},
"earning_type": "hourly",
"quantity": 8,
"rate": 30.0,
"bill_rate": 65.0,
"metadata": {
"jobID": "19834673",
"description": "Piecework pay"
}
}
```
# Update Payment Item
Source: https://docs.zeal.com/reference/payment-items/update-payment-item
openapi/zeal-api.json patch /payment-items
Update fields on an existing payment item by paymentItemID.
Updates an existing [Payment Item](/reference/payment-items/payment-item-object).
`earning_type` cannot be changed from rate-based to fixed amount or vice versa.
# Get Preview
Source: https://docs.zeal.com/reference/preview/get-preview
openapi/zeal-api.json get /preview
Retrieve a previously generated payroll preview by job ID.
# Get Next Available Check/Pay Date
Source: https://docs.zeal.com/reference/preview/get-preview-available-date
openapi/zeal-api.json get /preview/availableDate
Retrieve the next feasible check or pay date for employee checks or contractor payments based on speed and disbursement method.
# Preview Check Data
Source: https://docs.zeal.com/reference/preview/preview-check-data
openapi/zeal-api.json post /preview/checkData
Preview calculated pay, tax, and deduction data for a single employee check before it is created.
# Preview Overtime Checks
Source: https://docs.zeal.com/reference/preview/preview-overtime-checks
openapi/zeal-api.json post /preview/checks/ot
Generate a job ID to preview payroll calculations that include overtime-eligible shift hours for pending checks.
# Preview Payroll by Check Date
Source: https://docs.zeal.com/reference/preview/preview-payroll-by-check-date
openapi/zeal-api.json post /preview/checkDate
Generate a payroll preview job for all pending checks on a given check date.
# Preview Payroll by Check IDs
Source: https://docs.zeal.com/reference/preview/preview-payroll-by-check-ids
openapi/zeal-api.json post /preview/checks
Generate a payroll preview job for one or more pending checks by employee check ID.
# Get Reserve Balance
Source: https://docs.zeal.com/reference/provider-accounts/get-reserve-balance
openapi/zeal-api.json get /provider-accounts/balances
Retrieve reserve account balances for a company, optionally filtered by account type and date range.
# Create Cash Requirements Report
Source: https://docs.zeal.com/reference/reports/create-cash-requirements-report
openapi/zeal-api.json post /reports/cash-requirements
Start an asynchronous job to generate a Cash Requirements report showing the funds a company needs to cover an upcoming payroll run.
# Create Custom Payroll Journal Report
Source: https://docs.zeal.com/reference/reports/create-custom-payroll-journal-report
openapi/zeal-api.json post /reports/custom-payroll-journal
Start an asynchronous job to generate a customizable Payroll Journal report with configurable columns and grouping.
# Create Deduction Summary Report
Source: https://docs.zeal.com/reference/reports/create-deduction-summary-report
openapi/zeal-api.json post /reports/deductions-summary
Start an asynchronous job to generate a Deduction Summary report listing employee deductions within a date range, broken down by deduction type.
# Create KYC Summary Report
Source: https://docs.zeal.com/reference/reports/create-kyc-summary-report
openapi/zeal-api.json post /reports/kyc-summary
Create a report containing KYC flagged workers by company.
This endpoint is subject to frequent changes.
Creates a KYC Summary report, returning KYC flagged workers for a specified company and utilizing optional filters such as employment status or KYC status.
This endpoint returns a `job_id` instead of the raw data itself. Because the data returned can be large, Zeal uses a job queue to process the report instead of returning it synchronously. Once the [job status](/reference/reports/get-job-status) is marked as **complete**, the report can be downloaded using the [Get Report Download](/reference/reports/get-report-download) endpoint.
### Example Response - 200
```json theme={null}
{
"success": true,
"data": {
"job_id": "707ce36e-2267-2088-9fc4-c34d57c69c72",
"status": "pending",
"request_body": {
"companyID": "fe93448eueowej923474124eeze9",
"employment_status": "live",
"kyc_status": "all",
"media_type": "csv"
},
"created_at": "2024-02-29T18:21:28.951Z"
}
}
```
### Example Response - 400
```json theme={null}
{
"success": false,
"errors": [
{
"message": "Must provide a valid companyID",
"code": 50
}
]
}
```
# Create Labor Allocation Report
Source: https://docs.zeal.com/reference/reports/create-labor-allocation-report
openapi/zeal-api.json post /reports/labor-allocation
Start an asynchronous job to generate a Labor Allocation report showing how labor hours and costs are distributed across cost centers or departments.
# Create Payment Summary Report
Source: https://docs.zeal.com/reference/reports/create-payment-summary-report
openapi/zeal-api.json post /reports/payment-summary
Start an asynchronous job to generate a Payment Summary report summarizing employee and contractor payments within a date range.
# Create Payroll Journal Report
Source: https://docs.zeal.com/reference/reports/create-payroll-journal-report
openapi/zeal-api.json post /reports/payroll-journal
Start an asynchronous job to generate a Payroll Journal report with a detailed breakdown of payroll checks processed within a date range.
# Create Paystub Report
Source: https://docs.zeal.com/reference/reports/create-paystub-report
openapi/zeal-api.json post /reports/paystub
Start an asynchronous job to generate paystub documents for employee checks within a date range.
# Create Quarter to Date Report
Source: https://docs.zeal.com/reference/reports/create-quarter-to-date-report
openapi/zeal-api.json post /reports/qtd
Start an asynchronous job to generate a Quarter to Date (QTD) report summarizing cumulative payroll totals for a company.
# Create Worker Summary Report
Source: https://docs.zeal.com/reference/reports/create-worker-summary-report
openapi/zeal-api.json post /reports/worker-summary
Start an asynchronous job to generate a Worker Summary report covering employee and contractor details for a company.
# Create Year to Date Report
Source: https://docs.zeal.com/reference/reports/create-year-to-date-report
openapi/zeal-api.json post /reports/ytd
Start an asynchronous job to generate a Year to Date (YTD) report summarizing cumulative payroll totals for a company.
# Get Job Status
Source: https://docs.zeal.com/reference/reports/get-job-status
openapi/zeal-api.json get /reports
Poll the status of a previously submitted report job and retrieve the download URL once the job completes.
# Get Report Download
Source: https://docs.zeal.com/reference/reports/get-report-download
openapi/zeal-api.json get /reports/downloads
Download the completed file for a previously generated report job.
# Get Taxable Location by ID
Source: https://docs.zeal.com/reference/taxable-locations/get-taxable-location-by-id
openapi/zeal-api.json get /taxableLocations
Retrieve an existing Taxable Location object in Zeal's system by its taxableLocationID.
# Resolve Taxable Location
Source: https://docs.zeal.com/reference/taxable-locations/resolve-taxable-location
openapi/zeal-api.json post /taxableLocations
Find or create a Taxable Location object in Zeal's system. This request will try to match an existing record with a case-sensitive search.
# Taxable Location Object
Source: https://docs.zeal.com/reference/taxable-locations/taxable-location-object
The Taxable Location Object represents an address that describes its suitability for use as a work location or residency.
The Taxable Location Object represents an address that describes its suitability for use as a work location or residency. Resolve one via [`POST /taxableLocations`](/reference/taxable-locations/resolve-taxable-location).
> **Note:** Zeal utilizes a third-party validation tool to ensure a provided address is valid and mail-deliverable.
| attribute | type | description |
| :------------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `taxableLocationID` | string | Unique identifier representing this address |
| `street1` | string | Address Line 1 (Street name) |
| `street2` | string | Address Line 2 (Apt/Suite). Empty string if not applicable |
| `city` | string | City/Subdivision |
| `country` | string | Country for the address. One of `US` or `CA`. Defaults to `US` when resolving **NOTE: `CA` is only applicable for Canadian Payroll (Early Access)** |
| `state` | string | US State or Territory (2-letter abbreviation, see [ANSI](https://www.census.gov/library/reference/code-lists/ansi/ansi-codes-for-states.html)). Used when `country` is `US` |
| `zip` | string | ZIP code (5 digits). Used when `country` is `US` |
| `province` | string | Canadian province/territory (2-letter abbreviation: `AB`, `BC`, `MB`, `NB`, `NL`, `NS`, `NT`, `NU`, `ON`, `PE`, `QC`, `SK`, `YT`). Used when `country` is `CA` **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| `postal_code` | string | Canadian postal code. Used when `country` is `CA` **NOTE: Only applicable for Canadian Payroll (Early Access)** |
| `is_suitable_for_taxation` | boolean | Flag indicating whether a location is suitable for use as a work location and/or residency. If false, one or more of the following flags will be set. |
| `is_po_box` | boolean | PO Box addresses are mailing addresses but are not suitable for taxation |
| `is_state_mismatch` | boolean | An address's resolved geo-location must match the specified state or it is considered unsuitable for taxation |
| `is_armed_forces_address` | boolean | Armed Forces (APO/FPO/DPO) addresses are suitable for mailing but not for taxation purposes. Use the employee's last US address for residency purposes. |
| `is_foreign_address` | boolean | Foreign addresses are suitable for mailing but not for taxation purposes |
| `is_deliverable` | boolean | The address can accept mail and delivery |
```json EXAMPLE SUITABLE US TAXABLE LOCATION OBJECT theme={null}
{
"taxableLocationID": "609ffdf81a5f9c4c10b0c443",
"street1": "1 Ferry Building",
"street2": "",
"city": "San Francisco",
"country": "US",
"state": "CA",
"zip": "94111",
"is_suitable_for_taxation": true,
"is_po_box": false,
"is_state_mismatch": false,
"is_armed_forces_address": false,
"is_foreign_address": false,
"is_deliverable": true
}
```
```json EXAMPLE SUITABLE CANADIAN TAXABLE LOCATION OBJECT theme={null}
{
"taxableLocationID": "609ffdf81a5f9c4c10b0c443",
"street1": "100 Queen St W",
"street2": "",
"city": "Toronto",
"country": "CA",
"province": "ON",
"postal_code": "M5H 2N2",
"is_suitable_for_taxation": true,
"is_po_box": false,
"is_state_mismatch": false,
"is_armed_forces_address": false,
"is_foreign_address": false,
"is_deliverable": true
}
```
# Card Object
Source: https://docs.zeal.com/reference/wallet/card-object
The Zeal object representing a worker's card used for Instant Pay transfers.
| attribute | type | description |
| :------------- | :----- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cardID` | string | Zeal Card ID |
| `companyID` | string | Zeal Company ID |
| `employeeID` | string | Zeal Employee ID |
| `contractorID` | string | Zeal Contractor ID |
| `status` | string | Holds one of the following values:
`active`: card is successfully captured and can be used for transactions
`deleted`: card was manually removed or deactivated by the worker
`inactive`: card is no longer active due to failed onboarding, card expiration, or another system-related issue |
```json theme={null}
{
"cardID": "3677d374ba54a7aca8aa644be4c94776",
"companyID": "bf015b00e052f60cfb0e4a0d",
"employeeID": "d210f054bf5b006f50aecbe0",
"contractorID": null,
"status": "active",
"last_four": "0432"
}
```
# Get Card
Source: https://docs.zeal.com/reference/wallet/get-card
openapi/zeal-api.json get /card
Retrieve card information for an employee or contractor by companyID and employeeID or contractorID.
# Get Wallet Balance
Source: https://docs.zeal.com/reference/wallet/get-wallet-balance
openapi/zeal-api.json get /wallet
Retrieve the wallet balance for an employee or contractor by companyID and employeeID or contractorID.
# Get Wallet Transactions
Source: https://docs.zeal.com/reference/wallet/get-wallet-transactions
openapi/zeal-api.json get /wallet/transactions
Retrieve wallet transactions for an employee or contractor by companyID and employeeID or contractorID.
# Transfer Funds
Source: https://docs.zeal.com/reference/wallet/transfer-funds
openapi/zeal-api.json post /wallet/transfer
Transfer funds to an employee or contractor's card, optionally connected to an employee check or contractor payment.
# Wallet Transaction Object
Source: https://docs.zeal.com/reference/wallet/wallet-transaction-object
A Wallet Transaction represents the movement of funds into (credit) or out of (debit) the worker's Instant Pay Wallet.
| attribute | type | description |
| :-------------------- | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `walletTransactionID` | string | Zeal Transaction ID |
| `type` | enum | Holds one of the following values:
`credit` : this represents a positive contribution to the wallet balance (net pay credits)
`debit`: this represents a negative contribution to the wallet balance (push-to-card transfers) |
| `companyID` | string | Zeal Company ID |
| `employeeID` | string | Zeal Employee ID |
| `contractorID` | string | Zeal Contractor ID |
| `cardID` | string | ID of card used in transaction |
| `bankAccountID` | string | ID of bank account used in transaction |
| `status` | string | Holds one of the following values: `processing`, `settled`, `returned` |
| `description` | string | Description of transaction |
| `gross_amount` | float | Gross amount of transaction, before any fees. |
| `net_amount` | float | Net amount the transaction , after any fees. In the case of `debit` type, this is the amount the worker receives |
| `partner_fee` | float | Partner fees on the push-to-card transfer. Only applicable for `debit` type, otherwise \$0. |
| `zeal_fee` | float | Zeal fees on the push-to-card transfer. Only applicable for `debit` type, otherwise \$0. |
| `last_four` | string | Last four digits of card number. Only applicable for `debit` type. |
| `date` | string | Timestamp of transaction |
```json EXAMPLE WALLET TRANSACTION theme={null}
{
"walletTransactionID": "c2213b02e052f60cfb0e4ba4",
"type": "debit",
"companyID": "bf015b00e052f60cfb0e4a0d",
"employeeID": "d210f054bf5b006f50aecbe0",
"contractorID": null,
"bankAccountID": null,
"cardID": "10c313104851406408f4130be0540451",
"status": "settled",
"description": "Instant transfer",
"gross_amount": 102,
"partner_fee": 1,
"zeal_fee": 1,
"net_amount": 100,
"last_four": "0432",
"date": "2025-08-01T23:00:00.000Z"
}
```
A Wallet Transaction represents the movement of funds into (credit) or out of (debit) the worker's Instant Pay Wallet.
If the transaction is `debit` type:
* This represents a **push to card transfer** out of a worker's wallet to their card
* If you have a Charge Policy set up with Instant Pay, Zeal will apply your partner fee and the Zeal fee on transfers out of the wallet. The resulting `net_amount` is what the worker will receive to their card
* The last four digits of the worker's card that receives the funds is stored on the transaction object
If `credit` type:
* This represents a payment made to the wallet, such as **net pay credits**
* The gross amount and net amount will be equal since there are no fees
# Bank Account Event
Source: https://docs.zeal.com/reference/webhooks/bank-account-event
POSTs a request containing Bank Account details when it is created or updated.
This endpoint specifies what will be sent to your Bank Account Webhook. Zeal POSTs a request containing Bank Account details when it is created or updated. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Returns
Doesn't return anything but rather POSTs a request with Bank Account details.
***
## Raw Content Example
```json Bank Account theme={null}
{
"test": true,
"type": "create",
"bankAccountID": "fadd40898dd146c8b27b9ba02230edc7",
"workerID": "6964ba87007540ce4c2f5d39",
"companyID": "108e4a2f1e16487eb56d446077f5454d",
"worker_type": "employee",
"account_type": "checking",
"routing_number": "031176110",
"transit_number": null,
"institution_number": null,
"account_number_last_four": "6110",
"institution_name": "Capital One",
"is_primary": false,
"bank_accounts_count": 2,
"created_at": "2026-04-06T22:20:11.073Z",
"updated_at": "2026-04-06T22:20:11.073Z",
"timestamp": "2026-04-06T22:20:11Z"
}
```
# Company Event
Source: https://docs.zeal.com/reference/webhooks/company-event
POSTs a request upon update of a Company object.
This endpoint specifies what will be sent to your Company Update Webhook. Zeal POSTs a request containing a [The Company Object](/reference/companies/the-company-object) once it is successfully updated in the application. You can update and test the webhook URL you want Zeal to hit on the 'API' page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------- | ------- | ------------------------------------------------------- |
| test | boolean | Whether the company was updated in Test Mode |
| type | string | The operation that was applied to this company `update` |
Other [The Company Object](/reference/companies/the-company-object) fields
***
## Returns
Doesn't return anything but rather POSTs [The Company Object](/reference/companies/the-company-object) to your webhook URL
***
## Raw Content Example
```json theme={null}
{
"type": "update",
"companyID": "123456789",
"status": "live",
"first_name": "Test",
"last_name": "Employer",
"email": "test@demo.com",
"business_name": "Test Company",
"business_ein": "123456789",
"business_phone": "+13456789012",
"business_address": "1 Ferry Building",
"business_city": "San Francisco",
"business_state": "CA",
"business_zip": "94105",
"mail_address": "1 Ferry Building",
"mail_city": "San Francisco",
"mail_state": "CA",
"mail_zip": "94105",
"skip_migration": true,
"account_number": "567789343",
"routing_number": "567789343",
"requirements": [],
"onboarding_url": "/employeronboard/123456789?companyID=123456789&classification=TEST&use_bank_verification=true",
"is_sandbox": true,
"webhook_correlation_id": "Company One",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Company Onboarding Event
Source: https://docs.zeal.com/reference/webhooks/company-onboarding-event
POSTs a request upon completion of Company Onboarding.
This endpoint specifies what will be sent to your Company Onboarding Webhook. Zeal POSTs a request containing a [The Company Object](/reference/companies/the-company-object) once they complete the onboarding process in the application. You can update and test the webhook URL you want Zeal to hit on the 'API' page of the Zeal Dashboard.
***
## Request Body
| attributes | type | description |
| ------------------------ | ------ | ---------------------------------------------------------------------------------------------------------- |
| webhook\_correlation\_id | string | Webhook correlation ID that was set when creating the company onboarding link for this onboarding session. |
Other [The Company Object](/reference/companies/the-company-object) fields
***
## Returns
Doesn't return anything but rather POSTs [The Company Object](/reference/companies/the-company-object) to your webhook URL
***
## Raw Content Example
```json theme={null}
{
"companyID": "123456789",
"status": "live",
"first_name": "Test",
"last_name": "Employer",
"email": "test@demo.com",
"business_name": "Test Company",
"business_ein": "123456789",
"business_phone": "+13456789012",
"business_address": "1 Ferry Building",
"business_city": "San Francisco",
"business_state": "CA",
"business_zip": "94105",
"mail_address": "1 Ferry Building",
"mail_city": "San Francisco",
"mail_state": "CA",
"mail_zip": "94105",
"skip_migration": true,
"account_number": "567789343",
"routing_number": "567789343",
"requirements": [],
"onboarding_url": "/employeronboard/123456789?companyID=123456789&classification=TEST&use_bank_verification=true",
"is_sandbox": true,
"webhook_correlation_id": "Company One",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Contractor Event
Source: https://docs.zeal.com/reference/webhooks/contractor-event-webhook
Details on the Contractor Event webhook - when it fires, the full payload schema, and how to configure your receiving endpoint in the Partner Dashboard.
The Contractor Event is a webhook Zeal sends to your platform when a 1099 contractor completes the onboarding flow. It fires automatically when the contractor finishes the white-label Contractor Onboarding component, signaling that their personal information and W-9 data have been collected and their `onboarded` status is now `true`.
Use this event to update contractor records in your platform, trigger 1099 filing preparation steps, or unlock payment capabilities without polling the Zeal API for status changes.
Configure your webhook URL in the **Partner Dashboard** → **API page** → **Contractor Event** tab. Zeal delivers the payload to your URL every time a contractor in any of your companies completes onboarding.
***
## When the Event Fires
The Contractor Event is triggered when a contractor successfully completes the self-service white-label Contractor Onboarding flow. Zeal automatically sets the contractor's `onboarded` field to `true` and sends this webhook immediately afterward.
***
## Webhook Request
Zeal sends an HTTP POST to your configured endpoint with a `Content-Type: application/json` header and a `Puzzl-Signature` header for verification. Check that the `Puzzl-Signature` value matches your Webhook Secret from the Partner Dashboard before processing the payload.
**Headers**
| Header | Description |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `Content-Type` | `application/json` |
| `Puzzl-Signature` | Contains your Webhook Secret; verify it matches the secret shown in your Partner Dashboard |
***
## Payload Schema
**Example Payload**
```json theme={null}
{
"event": "contractor_onboarding",
"contractorID": "ctr_abc789def012",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"onboarded": true,
"timestamp": "2024-01-17T11:22:45.000Z",
"data": {
"contractorID": "ctr_abc789def012",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"first_name": "Monica",
"last_name": "Hall",
"email": "monica@piedpiper.com",
"type": "individual",
"onboarded": true,
"created_at": "2024-01-12T14:00:00.000Z",
"updated_at": "2024-01-17T11:22:45.000Z"
}
}
```
**Top-level Fields**
Always `"contractor_onboarding"` for this event type.
The unique Zeal identifier for the contractor who completed onboarding.
The ID of the company this contractor is associated with.
Always `true` when this event fires, confirming the contractor's onboarding is complete.
The ISO 8601 datetime at which the event was generated.
A snapshot of the contractor record at the time of the event.
The unique identifier for the contractor.
The ID of the employer company this contractor works for.
The contractor's first name.
The contractor's last name.
The contractor's email address.
Whether the contractor is an `"individual"` or a `"business"` entity.
The contractor's onboarding status (`true` when fully onboarded).
The ISO 8601 datetime when the contractor record was created.
The ISO 8601 datetime when the contractor record was last updated.
***
## Responding to the Event
Return an HTTP `200` status code to acknowledge receipt of the webhook. If your endpoint returns a non-2xx response, Zeal may retry delivery. Ensure your event handler is idempotent so that retried deliveries do not produce duplicate side effects.
***
## Configuring the Webhook URL
1. Log in to the **Partner Dashboard**.
2. Navigate to the **API** page.
3. Click the **Contractor Event** tab.
4. Enter your receiving endpoint URL.
5. Save. Zeal begins delivering contractor onboarding events to that URL immediately.
# Contractor Payment Event
Source: https://docs.zeal.com/reference/webhooks/contractor-payment-event
POSTs a request when a contractor payment is created, updated, or deleted in the Zeal dashboard.
This endpoint specifies what will be sent to your Contractor Payment Webhook. Zeal POSTs a request containing a [Contractor Payment Object](/reference/contractor-payments/contractor-payment-object) when it has been created, updated, or deleted in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------- | ------- | -------------------------------------------------------------------------- |
| test | boolean | Whether the Contractor Payment was created/updated/deleted in Test Mode |
| type | string | The operation that was applied to this payment. `create` `update` `delete` |
Other [Contractor Payment Object](/reference/contractor-payments/contractor-payment-object) fields.
***
## Returns
Doesn't return anything but rather POSTs a request with any changes in the Contractor Payment to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"operation_type": "update",
"first_name": "Erlich",
"middle_name": null,
"last_name": "Bachman",
"status": "pending",
"approval_required": false,
"approved": false,
"contractorPaymentID": "6a235c591cf39b4e37c6d4a8",
"contractorID": "69424c8fa2b8c4b55d3ff02e",
"companyID": "c9f2b8caa768409e84e98b0aba9d2ba8",
"pay_date": "2026-06-05",
"metadata": {},
"disbursement": {
"method": "direct_deposit",
"history": [],
"status": "pending"
},
"deductions": [
{
"deductionID": "6ba7b8109dad11d180b400c00c04fd4",
"companyID": "c9f2b8caa768409e84e98b0aba9d2ba8",
"deduction_type": "miscellaneous",
"deduction_template_name": "Example withholding",
"employee_contribution": {
"value": 10,
"contribution_type": "dollars"
},
"employee_calculated_contribution": 10
}
],
"has_payment_items": true,
"payment_items": [
{
"paymentItemID": "07439560e2cb4b3e801bcf0f5bc09a44",
"earning_type": "hourly",
"quantity": 2,
"rate": 50,
"gross_amount": 100,
"metadata": {
"jobID": "19834673",
"description": "Piecework pay"
}
}
],
"totals": {
"gross_amount": 100,
"net_amount": 90,
"deductions": 10
},
"timestamp": "2026-06-02T21:29:42Z"
}
```
# Create Employee Event
Source: https://docs.zeal.com/reference/webhooks/create-employee-event
POSTs a request upon creation of an employee in the Zeal dashboard.
This endpoint specifies what will be sent to your Create Employee Webhook. Zeal POSTs a request containing an [The Employee Object](/reference/employees/the-employee-object) once the employee has been created in the dashboard. You can update the webhook URL you want Zeal to hit on the 'API' page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------------------------------------------------------------- | ------- | ----------------------------------------------- |
| test | boolean | Whether the worker was "onboarded" in Test Mode |
| companyID | string | Zeal companyID of Employer |
| business\_name | string | Business Name of Employer |
| [The Employee Object](/reference/employees/the-employee-object) | string | Other employee object fields |
***
## Returns
Doesn't return anything, rather POSTs [The Employee Object](/reference/employees/the-employee-object) & data to the webhook URL
***
## Raw Content Example
```json theme={null}
{
"type": "create",
"test": true,
"companyID": "083472985",
"employeeID": "1234567890",
"onboarded": false,
"employment_status": "live",
"first_name": "Erlich",
"middle_initial": "A",
"last_name": "Bachman",
"dob": "1990-01-01",
"start_date": "2023-05-01T20:46:27.961Z",
"term_date": null,
"ssn": "123456789",
"phone_number": "+13456778934",
"email": "test@demo.com",
"title": "Manager",
"workLocationID": "123456789012345",
"address": "1 Market St.",
"address_line2": null,
"city": "San Francisco",
"state": "CA",
"zip": "10000",
"default_pay_schedule": "daily",
"default_wage": 20,
"default_ot_wage": 30,
"default_dt_wage": 40,
"autopilot": {
"autopilot_on": false,
"salary": null,
"salary_firstDate": null
},
"is_943": false,
"is_scheduleH": false,
"metadata": {},
"business_name": "Test Company",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Customer Account Event
Source: https://docs.zeal.com/reference/webhooks/customer-account-event
POSTs a request upon update of a Customer Account object.
POSTs a request upon update of a Customer Account object.
This endpoint specifies what will be sent to your Customer Account Update Webhook. Zeal POSTs a request containing a [Customer Account Object](/reference/customer-accounts/customer-account-object) once it is successfully updated in the application. You can update and test the webhook URL you want Zeal to hit on the 'API' page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------- | ------- | ------------------------------------------------------ |
| test | boolean | Whether the customer account was updated in Test Mode |
| type | string | The operation that was applied to this company`update` |
Other [Customer Account Object](/reference/customer-accounts/customer-account-object) fields
***
## Returns
Doesn't return anything but rather POSTs [Customer Account Object](/reference/customer-accounts/customer-account-object) to your webhook URL
***
## Raw Content Example
```json theme={null}
{
"type":"update",
"customer_account_id": "23b9ada702984edeb1496c1cb95abc8c",
"company_id": "dcb3bd9403ad41c98bbc2b4d54d88a44",
"partner_id": "c133eed2c9b8419ba2f22dc059bd445a",
"code": "customer-code-2",
"business_name": "Taco Bell",
"ein": "777777777",
"legal_structure": "llc",
"phone": "1234567890",
"email": "[email protected]",
"business_address": "1 ferry building",
"business_city": "San francisco",
"business_state": "CA",
"business_zip": "94103",
"business_owner": {
"first_name": "Erlich",
"last_name": "Bachman",
"email": "[email protected]",
"ssn": "345237890",
"dob": "1990-01-01",
"title": "CEO",
"ownership_percentage": 47,
"owner_type": "authorized_signer",
"address": "1600 Pennsylvania Ave NW",
"city": "Washington",
"state": "DC",
"zip": "20500"
},
"status": "live",
"is_sandbox":true,
"funding_source": {
"account_number": "849201923",
"account_type": "checking",
"routing_number": "314074269"
},
}
```
# Customer Account Onboarding Event
Source: https://docs.zeal.com/reference/webhooks/customer-account-onboarding-event
POSTs a request upon completion of Company Onboarding.
POSTs a request upon completion of Company Onboarding.
This endpoint specifies what will be sent to your Customer Account Onboarding Webhook. Zeal POSTs a request containing a [Customer Account Object](/reference/customer-accounts/customer-account-object) once they complete the onboarding process in the application. You can update and test the webhook URL you want Zeal to hit on the 'API' page of the Zeal Dashboard.
***
## Request Body
| attributes | type | description |
| ------------------------ | ------ | ---------------------------------------------------------------------------------------------------------- |
| webhook\_correlation\_id | string | Webhook correlation ID that was set when creating the company onboarding link for this onboarding session. |
Other [Customer Account Object](/reference/customer-accounts/customer-account-object) fields
***
## Returns
Doesn't return anything but rather POSTs [Customer Account Object](/reference/customer-accounts/customer-account-object) to your webhook URL
***
## Raw Content Example
```json theme={null}
{
"customer_account_id": "23b9ada702984edeb1496c1cb95abc8c",
"company_id": "dcb3bd9403ad41c98bbc2b4d54d88a44",
"partner_id": "c133eed2c9b8419ba2f22dc059bd445a",
"code": "customer-code-2",
"business_name": "Taco Bell",
"ein": "777777777",
"legal_structure": "llc",
"phone": "1234567890",
"email": "[email protected]",
"business_address": "1 ferry building",
"business_city": "San francisco",
"business_state": "CA",
"business_zip": "94103",
"business_owner": {
"first_name": "Erlich",
"last_name": "Bachman",
"email": "[email protected]",
"ssn": "345237890",
"dob": "1990-01-01",
"title": "CEO",
"ownership_percentage": 47,
"owner_type": "authorized_signer",
"address": "1600 Pennsylvania Ave NW",
"city": "Washington",
"state": "DC",
"zip": "20500"
},
"status": "live",
"is_sandbox":true,
"funding_source": {
"account_number": "849201923",
"account_type": "checking",
"routing_number": "314074269"
},
}
```
# Employee Check Event
Source: https://docs.zeal.com/reference/webhooks/employee-check-event
POSTs a request when an employee check is created, updated, or deleted in the Zeal dashboard.
This endpoint specifies what will be sent to your Employee Check Webhook. Zeal POSTs a request containing an Employee Check Object when it has been created, updated, or deleted in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| -------------- | ------- | --------------------------------------------------------------------------------- |
| test | boolean | Whether the employee check was created/updated/deleted in Test Mode |
| type | string | The operation that was applied to this employee check. `create` `update` `delete` |
| business\_name | string | Business Name of Employer |
Other Employee Check Object fields.
***
## Returns
Doesn't return anything but rather POSTs a request with any changes in the Employee Check Object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"type": "create",
"companyID": "df2a785b82cb4f46b765a8580e7e9c2f",
"business_name": "Test Company",
"employeeCheckID": "2edc78f8b8e14f6098e1b2687082d86c",
"employerCheckID": null,
"employeeID": "3a497f82e0c14b24a6a53eb451a0bb56",
"reportingPeriodID": "7a9e3a34b6f84f1d9f826a27f5cb34aa",
"status": "pending",
"is_salary": false,
"approval_required": false,
"approved": false,
"first_name": "Erlich",
"middle_initial": null,
"last_name": "Bachman",
"check_date": "2023-12-07T00:00:00Z",
"metadata": {},
"disbursement": {
"method": "direct_deposit",
"history": [],
"status": "pending"
},
"gross_pay": 40,
"net_pay": null,
"taxes": [],
"total_employer_taxes": null,
"total_employee_taxes": null,
"totals": {
"gross_earnings": null,
"gross_pay": null,
"net_pay": null,
"employer_taxes": null,
"employee_taxes": null,
"employee_deductions": null,
"employee_garnishments": null,
"employer_deductions": null,
"company_debit": null,
"company_cash_requirement": null
},
"shifts": [
{
"employeeID": "1234567890",
"shiftID": "123456789",
"employeeCheckID": "9827465739",
"status": "pending",
"first_name": "erlich",
"last_name": "bachman",
"metadata": {},
"wcc_code": null,
"workLocationID": 34567890,
"time": "2023-11-12T10:00:00",
"hourly": {
"hours": 2,
"wage": 20
}
}
],
"deductions": [],
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Employee E-Verify Update Event (Early Access)
Source: https://docs.zeal.com/reference/webhooks/employee-e-verify-update-event
POSTs request when there is an update to E-verify for an Employee.
This endpoint specifies what will be sent to your Employee E-verify Event Webhook. Zeal POSTs a request containing an Employee's E-verify information in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| test | boolean | Whether the Event was updated in Test Mode |
| companyID | string | Zeal `companyID` of Employer |
| employeeID | string | Zeal `employeeID` of Employee |
| first\_name | string | First name of Employee |
| last\_name | string | Last name of Employee |
| business\_name | string | Business Name |
| everify\_case\_number | string | Case number of the E-Verify request |
| everify\_status | string | Holds one of the following values:
`IN_PROGRESS`
`PENDING_REFERRAL`
`REFERRED`
`SUCCESS`
`FAILURE`
`FAILURE_NO_SHOW`
`FAILURE_NO_ACTION`
**NOTE: For more information on these statuses refer to the everify\_status field listed on the [Employee Object](/reference/employees/the-employee-object).** |
***
## Returns
Doesn't return anything but rather POSTs a request with the E-verify update to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"companyID": "1eeec343485723ee58ufefhz",
"business_name": "Test Company",
"employeeID": "1eeec343485723ee58ufefhz",
"first_name": "Erlich",
"last_name": "Bachman",
"everify_case_number": "2024270190310CF",
"everify_status": "SUCCESS",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Employee Event
Source: https://docs.zeal.com/reference/webhooks/employee-event
POSTs a request when the employee object has been updated in the Zeal dashboard.
This endpoint specifies what will be sent to your Employee Webhook. Zeal POSTs a request containing an [The Employee Object](/reference/employees/the-employee-object) when it has been updated in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| --------- | ------- | -------------------------------------------------------- |
| test | boolean | Whether the employee was updated in Test Mode |
| type | string | The operation that was applied to this employee `update` |
Other [The Employee Object](/reference/employees/the-employee-object) fields.
***
## Returns
Doesn't return anything but rather POSTs the updated or deleted Employee Object to the webhook URL.
***
## Raw Content Example
```json theme={null}
{
"type": "update",
"test": true,
"companyID": "083472985",
"employeeID": "1234567890",
"onboarded": true,
"employment_status": "live",
"first_name": "Erlich",
"middle_initial": "A",
"last_name": "Bachman",
"dob": "1990-01-01",
"start_date": "2023-05-01T20:46:27.961Z",
"term_date": null,
"ssn": "123456789",
"phone_number": "+13456778934",
"email": "test@demo.com",
"title": "Manager",
"workLocationID": "123456789012345",
"address": "1 Market St.",
"address_line2": null,
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"default_pay_schedule": "daily",
"default_wage": 20,
"default_ot_wage": 30,
"default_dt_wage": 40,
"is_943": false,
"is_scheduleH": false,
"metadata": {},
"business_name": "Test Company",
"timestamp": "2024-01-21T21:29:42Z",
"instant_pay_enabled": true
}
```
# Employee I9 Update Event (Early Access)
Source: https://docs.zeal.com/reference/webhooks/employee-i9-update-event
This endpoint specifies what will be sent to your Employee I9 Event Webhook.
This endpoint specifies what will be sent to your Employee I9 Event Webhook. Zeal POSTs a request containing an Employee's I9 information at different stages of the I9 completion in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Request Body
| attribute | type | description |
| -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| test | boolean | Whether the Event was created/updated/deleted in Test Mode |
| employeeID | string | Zeal `employeeID` of Employee |
| first\_name | string | First name of Employee |
| last\_name | string | Last name of Employee |
| companyID | string | Zeal `companyID` of Employer |
| business\_name | string | Business Name |
| documents | list | Document or documents provided by employee. Can contain multiple.
Show documents values:
`CANADIAN_DRIVERS_LICENSE` `DAY_CARE_RECORD` `DRIVERS_LICENSE` `DS_1350` `EMPLOYMENT_AUTHORIZATION_DOCUMENT` `FOREIGN_PASSPORT` `FOREIGN_PASSPORT_WITH_FORM_I94` `FOREIGN_PASSPORT_WITH_I551_STAMP` `FORM_I179` `FORM_I197` `FORM_I551` `FORM_I766` `FORM_I94` `FORM_I94_RECEIPT` `FS_240` `FS_545` `FSM_OR_RMI_PASSPORT_WITH_FORM_I94` `GOVERNMENT_ID_CARD` `HOSPITAL_RECORD` `MILITARY_DEPENDENT_ID_CARD` `NATIVE_AMERICAN_TRIBAL_DOCUMENT` `SCHOOL_ID_CARD` `SCHOOL_RECORD` `SOCIAL_SECURITY_CARD` `US_BIRTH_CERTIFICATE` `US_COAST_GUARD_CARD` `US_MILITARY_CARD` `US_PASSPORT` `VOTER_REGISTRATION_CARD` |
| status | string | Holds one of the following values:
`STARTED`
`SECTION_1_COMPLETED`
`AUTHORIZED_REPRESENTATIVE_CONTACTED`
`SECTION_2_COMPLETED` |
| authorized\_representative | object | Information on the Authorized Representative who reviewed the employee's I9
Show authorized\_representative fields:
*email*\* - Email of authorized representative, shown if provided
*phone*\* - Phone of authorized representative, shown if provided
*first\_name*\* - First name of authorized representative
*last\_name*\* - Last name of authorized representative
*decision*\* - Decision of authorized representative. Possible values: `IN_PROGRESS` `APPROVED` `CHANGES_REQUESTED`
*decision\_made\_on*\* - Date and time the decision was made on
**NOTE: The authorized\_representative object will not appear until the I9 status has reached AUTHORIZED\_REPRESENTATIVE\_CONTACTED and will only show all fields (either phone or email) once the status updates to SECTION\_2\_COMPLETED** |
| admin\_review\_status | string | Holds one of the following values:
`PENDING_REVIEW`
`CHANGES_REQUESTED`
`APPROVED`
**NOTE: You must have the admin review status feature enabled for your company for this field to appear and will generate after the authorized\_representative approves the I9 form request.** |
***
## Returns
Doesn't return anything but rather POSTs a request with the I9 update to your webhook URL.
***
## Raw Content Example
```json STARTED theme={null}
{
"test": false,
"employeeID": "cc4482374ee49487ruzieun",
"first_name": "Erlich",
"last_name": "Bachman",
"companyID": "1eeec343485723ee58ufefhz",
"business_name": "Test Company",
"documents": [],
"status": "STARTED",
"timestamp": "2024-01-21T21:29:42Z"
}
```
```json SECTION_1_COMPLETED theme={null}
{
"test": false,
"employeeID": "cc4482374ee49487ruzieun",
"first_name": "Erlich",
"last_name": "Bachman",
"companyID": "1eeec343485723ee58ufefhz",
"business_name": "Test Company",
"documents": [
"US_PASSPORT"
],
"status": "SECTION_1_COMPLETED",
"timestamp": "2024-01-21T21:29:42Z"
}
```
```json AUTHORIZED_REPRESENTATIVE_CONTACTED theme={null}
{
"test": false,
"employeeID": "cc4482374ee49487ruzieun",
"first_name": "Erlich",
"last_name": "Bachman",
"companyID": "1eeec343485723ee58ufefhz",
"business_name": "Test Company",
"documents": [
"US_PASSPORT"
],
"status": "AUTHORIZED_REPRESENTATIVE_CONTACTED",
"authorized_representative": {
"email": "test@demo.com"
}
}
```
```json SECTION_2_COMPLETED theme={null}
{
"test": false,
"employeeID": "cc4482374ee49487ruzieun",
"first_name": "Erlich",
"last_name": "Bachman",
"companyID": "1eeec343485723ee58ufefhz",
"business_name": "Test Company",
"documents": [
"US_PASSPORT"
],
"status": "SECTION_2_COMPLETED",
"authorized_representative": {
"first_name": "Richard",
"last_name": "Hendricks",
"email": "test@demo.com",
"decision": "APPROVED",
"decision_made_on": "2024-10-01T20:46:27.961Z"
},
"admin_review_status": "PENDING_REVIEW"
}
```
# Employee Onboarding Event
Source: https://docs.zeal.com/reference/webhooks/employee-onboarding-event
Details on the Employee Onboarding webhook event - when it fires, the full payload schema, and how to configure your receiving endpoint in Zeal.
The Employee Onboarding Event is a webhook Zeal sends to your platform when an employee successfully completes the onboarding flow. This event fires automatically when the employee's `onboarded` status is set to `true` - either programmatically via the API (`POST /employees/setOnboardedStatusToTrue`) or when the employee completes the white-label Employee Onboarding component.
Use this event to synchronize your platform's employee records, enable downstream features like direct deposit, or send the employee a welcome notification without polling the Zeal API.
Configure your webhook URL in the **Partner Dashboard** → **API page** → **Employee Onboarding Event** tab. Zeal will POST the payload to that URL every time an employee in any of your companies completes onboarding.
***
## When the Event Fires
The Employee Onboarding Event is triggered when:
* A partner or admin calls `POST /employees/setOnboardedStatusToTrue` via the API.
* An employee completes the self-service white-label Employee Onboarding flow (which automatically sets `onboarded` to `true` upon successful completion).
***
## Webhook Request
Zeal sends an HTTP POST to your configured endpoint with a `Content-Type: application/json` header and a `Puzzl-Signature` header containing your Webhook Secret. Verify the request by checking that the `Puzzl-Signature` value matches your Webhook Secret from the Partner Dashboard before processing the event.
**Headers**
| Header | Description |
| ----------------- | ------------------------------------------------------------------------------------------ |
| `Content-Type` | `application/json` |
| `Puzzl-Signature` | Contains your Webhook Secret; verify it matches the secret shown in your Partner Dashboard |
***
## Payload Schema
**Example Payload**
```json theme={null}
{
"event": "employee_onboarding",
"employeeID": "emp_6547etrc312314213",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"onboarded": true,
"timestamp": "2024-01-16T09:15:32.000Z",
"data": {
"employeeID": "emp_6547etrc312314213",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com",
"onboarded": true,
"created_at": "2024-01-10T08:00:00.000Z",
"updated_at": "2024-01-16T09:15:32.000Z"
}
}
```
**Top-level Fields**
Always `"employee_onboarding"` for this event type.
The unique Zeal identifier for the employee who completed onboarding.
The ID of the company this employee belongs to.
Always `true` when this event fires, confirming that onboarding is complete.
The ISO 8601 datetime at which the event was generated.
A snapshot of the employee record at the time of the event.
The unique identifier for the employee.
The ID of the employer company.
The employee's first name.
The employee's last name.
The employee's email address.
The employee's onboarding status (`true` when fully onboarded).
The ISO 8601 datetime when the employee record was created.
The ISO 8601 datetime when the employee record was last updated.
***
## Responding to the Event
Your endpoint must return an HTTP `200` status code to acknowledge receipt. If Zeal does not receive a `200` response, it may retry delivery. Process the event idempotently so that duplicate deliveries do not cause duplicate side effects in your system.
***
## Configuring the Webhook URL
1. Log in to the **Partner Dashboard**.
2. Navigate to the **API** page.
3. Click the **Employee Onboarding Event** tab.
4. Enter your endpoint URL.
5. Save. Zeal will start delivering events to that URL immediately.
# Employee Requirements Create Event
Source: https://docs.zeal.com/reference/webhooks/employee-requirements-create-event
This endpoint specifies what will be sent to your Employee Requirement Webhook.
This endpoint specifies what will be sent to your Employee Requirement Webhook. Zeal POSTs a request containing the Employee Requirement object. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Request Body
| attribute | type | description |
| --------------------- | ------- | --------------------------------------------------------- |
| test | boolean | Whether the Employee Requirement was created in Test Mode |
| employeeRequirementID | string | ID of the employee requirement |
| companyID | string | ID of company |
| employeeID | string | ID of employee |
| date | string | Date when the requirement was created |
| formTemplateID | string | ID of the form template |
| workLocationID | string | ID of the work location |
| jurisdiction | string | Jurisdiction of the requirement |
| type | string | Type of requirement |
| status | string | Status of requirement: `OPEN`, `CLOSED` |
***
## Returns
Doesn't return anything but rather POSTs a request with the Employee Requirement object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"employeeRequirementID": "a60efd68-e6ab-4db1-b4e6-fd7ee2888b3a",
"type": "FORM",
"status": "OPEN",
"jurisdiction": "US",
"formTemplateID": "form-aca0c649-ccd5-4c14-9337-f8d22d1fadc1",
"employeeID": "66fec7a8e62b170d86ce23d3",
"companyID": "23d5656d3511415b8354faf59f3486db",
"date": "2024-12-11T20:04:20.219Z",
"timestamp": "2024-12-11T20:04:20.219Z"
}
```
# Employee Requirements Update Event
Source: https://docs.zeal.com/reference/webhooks/employee-requirements-update-event
This endpoint specifies what will be sent to your Employee Requirement Webhook.
This endpoint specifies what will be sent to your Employee Requirement Webhook. Zeal POSTs a request containing the Employee Requirement object. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Request Body
| attribute | type | description |
| --------------------- | ------- | --------------------------------------------------------- |
| test | boolean | Whether the Employee Requirement was created in Test Mode |
| employeeRequirementID | string | ID of the employee requirement |
| companyID | string | ID of company |
| employeeID | string | ID of employee |
| date | string | Date when the requirement was created |
| formTemplateID | string | ID of the form template |
| workLocationID | string | ID of the work location |
| jurisdiction | string | Jurisdiction of the requirement |
| type | string | Type of requirement |
| status | string | Status of requirement: `OPEN`, `CLOSED` |
***
## Returns
Doesn't return anything but rather POSTs a request with the Employee Requirement object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"employeeRequirementID": "a60efd68-e6ab-4db1-b4e6-fd7ee2888b3a",
"type": "FORM",
"status": "CLOSED",
"jurisdiction": "US",
"formTemplateID": "form-aca0c649-ccd5-4c14-9337-f8d22d1fadc1",
"employeeID": "66fec7a8e62b170d86ce23d3",
"companyID": "23d5656d3511415b8354faf59f3486db",
"date": "2024-12-11T20:04:20.219Z",
"timestamp": "2024-12-11T20:04:20.219Z"
}
```
# Employer Check Created Event
Source: https://docs.zeal.com/reference/webhooks/employer-check-created-event
POSTs request when an employer check is created from existing pending checks.
This endpoint specifies what will be sent to your 'Employer Check Created' Webhook. Zeal POSTs a request containing an Employer Check Object created from pending checks, at 2 PM PT. You can update the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| test | boolean | Whether the employer check was created in Test Mode |
| companyID | string | Zeal companyID of Employer |
| business\_name | string | Business Name of Employer |
| employerCheckID | string | Employer Check ID |
| status | string | Will hold the following values: `pre-processed` |
| reporting\_periods | array | List of reporting periods contained in this employer check.
Show child attributes:
**reportingPeriodID** - type: string - description: Reporting Period ID |
| totals | object | Totals for this employer check stored in an object
Show child attributes:
**gross\_pay** - type: number - description: Gross pay for employee (total pay before taxes) |
| employee\_checks | array | List of all employee checks. Each object contains information regarding how each employee is paid for this payroll run (i.e. everything found on a paystub and more). See Employee Check Object for all attributes. |
***
## Returns
Doesn't return anything but rather POSTs the created Employer Check Object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"companyID": "083472985",
"business_name": "Test Company",
"employerCheckID": "123456789",
"status": "pre-processed",
"reporting_periods": [
"01739fc4cfd84c2e93dba5e802d1dda1"
],
"createdAt": "2024-03-28T21:00:07Z",
"totals": {
"gross_pay": 40,
"net_pay": 36.94,
"total_employer_taxes": 3.06,
"company_debit": 43.06,
"total_employee_taxes": 3.06
},
"employee_checks": [
{
"employeeCheckID": "9827465739",
"status": "pre-processed",
"employeeID": "0987654321",
"check_date": "2024-05-06T00:00:00Z",
"is_salary": false,
"approval_required": false,
"approved": false,
"first_name": "Peter",
"middle_initial": null,
"last_name": "Gregory",
"reportingPeriodID": "01739fc4cfd84c2e93dba5e802d1dda1",
"metadata": {},
"disbursement": {
"method": "direct_deposit",
"history": []
},
"gross_pay": 40,
"net_pay": null,
"taxes": [],
"total_employer_taxes": null,
"total_employee_taxes": null,
"totals": {
"gross_earnings": 40,
"gross_pay": 40,
"net_pay": 36.94,
"employer_taxes": 3.06,
"employee_taxes": 3.06,
"employee_deductions": null,
"employee_garnishments": null,
"employer_deductions": null,
"company_debit": 43.06,
"company_cash_requirement": 43.06
},
"shifts": [
{
"employeeID": "1234567890",
"shiftID": "123456789",
"employeeCheckID": "9827465739",
"status": "pending",
"first_name": "Peter",
"last_name": "Gregory",
"metadata": {},
"wcc_code": null,
"workLocationID": 34567890,
"time": "2024-01-12T10:00:00",
"hourly": {
"hours": 2,
"wage": 20
}
}
],
"deductions": []
}
],
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Employer Check Processed Event
Source: https://docs.zeal.com/reference/webhooks/employer-check-processed
POSTs a request when an employer check enters processing.
This endpoint specifies what will be sent to your 'Employer Check Processed' Webhook. Zeal POSTs a request containing the processed Employer Check Object (checks are typically processed at 2:00 PM PT). You can update the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| test | boolean | Whether the Employer Check was created in the Test Mode |
| companyID | string | Zeal companyID of Employer |
| business\_name | string | Business Name of Employer |
| employerCheckID | string | Employer Check ID |
| status | string | Status of shift. Will hold the following values: `processed` |
| reporting\_periods | array | List of reporting periods contained in this employer check.
Show child attributes:
**reportingPeriodID** - type: string - description: Reporting Period ID |
| totals | object | Totals for this employer check are stored in an object.
Show child attributes:
**gross\_pay** - type: number - description: Gross pay for an employee (total pay before taxes)
**net\_pay** - type: number - description: Net pay for an employee (total pay after taxes = `gross_pay - total_employee_taxes`)
**total\_employer\_taxes** - type: number - required: Total amount of employer taxes
**company\_debit** - type: number - description: Total cost for the company (`net_pay + total_employee_taxes + total_employer_taxes`)
**total\_employee\_taxes** - type: number - description: Total amount of employee taxes for this employer check run |
| employee\_checks | array | List of all employee checks. Each object contains information regarding how each employee is paid for this payroll run (i.e. everything found on a paystub and more). See Employee Check Object for all attributes |
***
## Returns
Doesn't return anything but rather POSTs the processed Employer Check Object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"companyID": "083472985",
"business_name": "Test Company",
"employerCheckID": "123456789",
"status": "processed",
"reporting_periods": [
{
"reportingPeriodID": "01739fc4cfd84c2e93dba5e802d1dda1",
"start": "2024-01-05T22:01:00.000Z",
"end": "2024-01-06T22:00:00.000Z"
}
],
"createdAt": "2024-02-13T19:22:34Z",
"totals": {
"gross_pay": 40,
"net_pay": 36.94,
"total_employer_taxes": 3.06,
"company_debit": 43.06,
"total_employee_taxes": 3.06
},
"employee_checks": [
{
"employeeID": "0987654321",
"check_date": "2024-01-06T00:00:00Z",
"is_salary": false,
"approval_required": false,
"approved": true,
"first_name": "Peter",
"middle_initial": null,
"last_name": "Gregory",
"reportingPeriodID": "01739fc4cfd84c2e93dba5e802d1dda1",
"status": "processed",
"metadata": {},
"disbursement": {
"method": "direct_deposit",
"history": []
},
"gross_pay": 40,
"net_pay": 36.94,
"total_employee_taxes": 3.06,
"total_employer_taxes": 3.06,
"taxes": [
{
"name": "Employee Medicare Tax",
"paidBy": "EMPLOYEE_WITHHOLDING",
"amount": 0.58
},
{
"name": "Employee Social Security Tax",
"paidBy": "EMPLOYEE_WITHHOLDING",
"amount": 2.48
},
{
"name": "Employer Medicare Tax",
"paidBy": "EMPLOYER_LIABILITY",
"amount": 0.58
},
{
"name": "Employer Social Security Tax",
"paidBy": "EMPLOYER_LIABILITY",
"amount": 2.48
}
],
"shifts": [
{
"employeeID": "0987654321",
"shiftID": "123456789",
"employeeCheckID": "9827465739",
"status": "processed",
"first_name": "Peter",
"last_name": "Gregory",
"metadata": {},
"wcc_code": null,
"workLocatio4ID": "34567890",
"time": "2023-01-12T10:00:00",
"hourly": {
"hours": 2,
"wage": 20
}
}
],
"deductions": []
}
],
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Employer Check Processed Webhook Lite
Source: https://docs.zeal.com/reference/webhooks/employer-check-processed-lite
A lite version of the Employer Check Processed Event Webhook that returns employee_checks as an array of employeeCheckIDs.
This endpoint is a lite version of the [Employer Check Processed Event Webhook](/reference/webhooks/employer-check-processed), this endpoint specifies what will be sent to your 'Employer Check Processed' Webhook. Zeal POSTs a request containing the processed Employer Check Object (checks are typically processed at 2:00 PM PT). Unlike the [Employer Check Processed Event Webhook](/reference/webhooks/employer-check-processed), the lite webhook returns `employee_checks` processed as an array of `employeeCheckID`'s rather than an entire array of employee check objects. You can update the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| test | boolean | Whether the Employer Check was created in the Test Mode |
| companyID | string | Zeal companyID of Employer |
| business\_name | string | Business Name of Employer |
| employerCheckID | string | Employer Check ID |
| status | string | Status of shift. Will hold the following values: `processed` |
| reporting\_periods | array | List of reporting periods contained in this employer check.
Show child attributes:
**reportingPeriodID** - type: string - description: Reporting Period ID |
| totals | object | Totals for this employer check stored in an object.
Show child attributes:
**gross\_pay** - type: number - description: Gross pay for an employee (total pay before taxes)
**net\_pay** - type: number - description: Net pay for an employee (total pay after taxes = `gross_pay - total_employee_taxes`)
**total\_employer\_taxes** - type: number - required: Total amount of employer taxes
**company\_debit** - type: number - description: Total cost for the company (`net_pay + total_employee_taxes + total_employer_taxes`)
**total\_employee\_taxes** - type: number - description: Total amount of employee taxes for this employer check run |
| employee\_checks | array | Returns array of all employeeCheckIDs moved to processed |
***
## Returns
Doesn't return anything but rather POSTs the processed Employer Check Object to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"companyID": "083472985",
"business_name": "Test Company",
"employerCheckID": "123456789",
"status": "processed",
"reporting_periods": [
"01739fc4cfd84c2e93dba5e802d1dda1"
],
"totals": {
"gross_pay": 40,
"net_pay": 36.94,
"total_employer_taxes": 3.06,
"company_debit": 43.06,
"total_employee_taxes": 3.06
},
"employee_checks": [
"9827465739"
],
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Garnishment Event
Source: https://docs.zeal.com/reference/webhooks/garnishment-event
POSTs garnishment lifecycle and payroll-scoped events to your garnishment webhook URL.
Zeal POSTs to your **Garnishment webhook** whenever a garnishment order changes or withholding is applied/reversed on a check or contractor payment. Configure the URL on the Partner Dashboard **API** page.
Use top-level `event_type` to distinguish events. Money fields are in **dollars**. Snapshot fields match the public garnishment API shape and always reflect **post-event** garnishment state. Optional fields are omitted when unset.
Event-specific fields:
* `satisfied` — includes `satisfied_reason`
* `applied` — includes exactly one payment identity (`employeeCheckID` + `check_date`, or `contractorPaymentID` + `payment_date`), plus `amount_withheld`, `cap_reason`, and `amount_before_cap`
* `reversed` — same payment identity + `amount_withheld` (no cap fields)
## Event types
| `event_type` | When it fires |
| ------------ | ----------------------------------------------------------- |
| `created` | Garnishment order created |
| `modified` | Order superseded by a new record |
| `vacated` | Court/order withdrawn |
| `canceled` | Canceled (mistake/duplicate/non-legal) |
| `satisfied` | Fully done (balance withheld or end date reached) |
| `applied` | Withholding applied on a check/payment (includes cap audit) |
| `reversed` | Prior apply undone (check/payment void/correction) |
There is no separate `capped` event — cap audit lives on `applied` via `cap_reason` and `amount_before_cap` (including `$0` starved applications).
When a void reverses an apply that had satisfied the order, Zeal sends `reversed` with the updated snapshot (`status` often returns to `active` when the end date has not passed).
## Returns
Doesn't return anything but rather POSTs a request with garnishment details.
***
## Raw Content Example
```json Created theme={null}
{
"test": true,
"event_type": "created",
"companyID": "108e4a2f1e16487eb56d446077f5454d",
"garnishmentID": "fadd40898dd146c8b27b9ba02230edc7",
"workerID": "6964ba87007540ce4c2f5d39",
"workerType": "employee",
"status": "active",
"garnishment_type": "child_support",
"priority": 1,
"total_amount_owed": 500,
"total_amount_withheld": 0,
"effective_start_date": "2026-01-01",
"agency_name": "Example Agency",
"agency_address": "123 Main St",
"cap_amount": 100,
"garnishment_state": "CA",
"case_id": "CASE-123",
"order_number": "ORD-456",
"created_at": "2026-07-29T17:00:00.000Z",
"updated_at": "2026-07-29T17:00:00.000Z",
"timestamp": "2026-07-29T17:00:00.000Z"
}
```
```json Applied theme={null}
{
"test": true,
"event_type": "applied",
"companyID": "108e4a2f1e16487eb56d446077f5454d",
"garnishmentID": "fadd40898dd146c8b27b9ba02230edc7",
"workerID": "6964ba87007540ce4c2f5d39",
"workerType": "employee",
"status": "active",
"garnishment_type": "child_support",
"priority": 1,
"total_amount_owed": 500,
"total_amount_withheld": 75,
"effective_start_date": "2026-01-01",
"agency_name": "Example Agency",
"agency_address": "123 Main St",
"cap_amount": 100,
"garnishment_state": "CA",
"case_id": "CASE-123",
"order_number": "ORD-456",
"employeeCheckID": "check_abc123",
"check_date": "2026-07-29",
"amount_withheld": 75,
"cap_reason": "percentage",
"amount_before_cap": 120,
"created_at": "2026-07-01T17:00:00.000Z",
"updated_at": "2026-07-29T17:00:00.000Z",
"timestamp": "2026-07-29T17:00:00.000Z"
}
```
# Instant Pay Wallet Transaction Event
Source: https://docs.zeal.com/reference/webhooks/instant-pay-wallet-transaction-event
This endpoint specifies what will be sent to your Instant Pay Wallet Webhook.
This endpoint specifies what will be sent to your Instant Pay Wallet Webhook. Zeal POSTs a request containing the Wallet Transaction object when there is a new credit or debit Wallet Transaction. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Returns
Doesn't return anything but rather POSTs a request with a Wallet Transaction.
***
## Raw Content Example
```json Wallet Credit Transaction theme={null}
{
"test": false,
"walletTransactionID": "c2213b02e052f60cfb0e4ba4",
"type": "credit",
"companyID": "bf015b00e052f60cfb0e4a0d",
"employeeID": "d210f054bf5b006f50aecbe0",
"contractorID": null,
"gross_amount": 1000,
"partner_fee": 0,
"zeal_fee": 0,
"net_amount": 1000,
"last_four": null,
"timestamp": "2024-01-21T21:29:42Z"
}
```
```json Wallet Debit Transaction (Transfer) theme={null}
{
"test": false,
"walletTransactionID": "c2213b02e052f60cfb0e4ba4",
"type": "debit",
"companyID": "bf015b00e052f60cfb0e4a0d",
"employeeID": "d210f054bf5b006f50aecbe0",
"contractorID": null,
"gross_amount": 102,
"partner_fee": 1,
"zeal_fee": 1,
"net_amount": 100,
"last_four": "0432",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Paperwork Submission Event
Source: https://docs.zeal.com/reference/webhooks/paperwork-submission-event
POSTs a request containing a Paperwork Submission Object when paperwork is submitted.
This endpoint specifies what will be sent to your Paperwork Submission Webhook. Zeal POSTs a request containing a Paperwork Submission Object when paperwork is submitted. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Returns
Doesn't return anything but rather POSTs a request with a Paperwork Submission Object.
***
## Raw Content Example
```json Paperwork Submission webhook theme={null}
{
"test": true,
"templateID": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"submissionID": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"submission_date": "2023-06-01T12:00:00Z",
"worker_type": "employee",
"companyID": "603d0f8f1c4b2a4e28c8f0b4",
"employeeID": "603d0f8f1c4b2a4e28c8f0b4",
"contractorID": null,
"jurisdiction": "VA",
"fields": {
"field1": "value1",
"field2": "value2"
},
"paperwork_type": "W4",
"url": "https://example.com/submission/12345"
}
```
# Paycard Onboarding Status Event (Early Access)
Source: https://docs.zeal.com/reference/webhooks/paycard-onboarding-status-event
POSTs request when Paycard Onboarding is shown to a worker.
POSTs request when Paycard Onboarding is shown to a worker.
This endpoint specifies what will be sent to your Paycard Onboarding Status Webhook. Zeal POSTs a request containing the paycard status for a worker during their paycard onboarding. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Request Body
| attribute | type | description |
| -------------- | -------- | -------------------------------------------------------------------- |
| test | boolean | Whether the Event was created/updated/deleted in Test Mode |
| companyID | string | Zeal `companyID` of Employer |
| employeeID | string | Zeal `employeeID` of worker (if the worker is of type Employee) |
| contractorID | string | Zeal `contractorID` of worker (if the worker is of type Contractor) |
| first\_name | string | First name of Worker |
| last\_name | string | Last name of Worker |
| business\_name | string | Business Name |
| status | string | Holds one of the following values:`requested``declined``provisioned` |
| timestamp | datetime | |
***
## Returns
Doesn't return anything but rather POSTs a request with the Paycard update to your webhook URL.
***
## Raw Content Example
```json theme={null}
{
"test": true,
"companyID": "1234ae8a477346e6900741c5301f1cc8",
"employeeID": "123ebd7dba526b6b852048f5",
"first_name": "Erlich",
"last_name": "Bachman",
"business_name": "Test Company",
"status": "requested",
"timestamp": "2024-01-21T21:29:42Z"
}
```
```json theme={null}
{
"test": true,
"companyID": "1234ae8a477346e6900741c5301f1cc8",
"employeeID": "123ebd7dba526b6b852048f5",
"first_name": "Erlich",
"last_name": "Bachman",
"business_name": "Test Company",
"status": "declined",
"timestamp": "2024-01-21T21:29:42Z"
}
```
```json theme={null}
{
"test": true,
"companyID": "1234ae8a477346e6900741c5301f1cc8",
"employeeID": "123ebd7dba526b6b852048f5",
"first_name": "Erlich",
"last_name": "Bachman",
"business_name": "Test Company",
"status": "provisioned",
"timestamp": "2024-01-21T21:29:42Z"
}
```
# Job Queue Event
Source: https://docs.zeal.com/reference/webhooks/report-status-change-webhook
POSTs a request whenever a report and its corresponding job is created or updated.
This endpoint specifies what will be sent to the Job Queue Event Webhook. Zeal POSTs an object with corresponding job information whenever a report is created or its status is updated.
***
## Request Body
| attribute | type | description |
| ---------- | ------ | -------------------------------------------------------------------------------------- |
| jobType | string | Corresponding job type - parameters could be PreviewCheckDate PreviewChecks or Reports |
| reportType | string | The type of report the job is for |
| companyID | string | Zeal `companyID` of Employer |
| status | string | Status of job |
| jobID | string | Corresponding job ID |
***
## Returns
Doesn't return anything, rather POSTs relevant job\_type & corresponding data to the webhook URL.
***
## Raw Content Example
```json theme={null}
{
"jobID": "01ea85bf-9cbf-4ad1-acf2-2a277dfe0f5b",
"status": "complete",
"reportType": "taxable_wage",
"companyID": "7456d5e912a74bc380fd5d1396fed8d2",
"business_name": "Test Company",
"createdAt": "2024-12-10T18:15:03.179Z",
"updatedAt": "2024-12-10T18:15:03.179Z",
"test": true,
"timestamp": "2024-12-10T18:15:03.179Z",
}
```
# Shift Event
Source: https://docs.zeal.com/reference/webhooks/shift-event
POSTs request when a shift has been created, updated, or deleted in the Zeal dashboard.
This endpoint specifies what will be sent to your Shift Event Webhook. Zeal POSTs a request containing a pending [Shift Object](/reference/employee-checks/shifts/shift-object) when they have been created, updated, or deleted in the dashboard. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
***
## Request Body
| attribute | type | description |
| -------------- | ------- | ------------------------------------------------------------------------ |
| test | boolean | Whether the Shift Event was created/updated/deleted in Test Mode |
| type | string | The operation that was applied to this shift. `create` `update` `delete` |
| companyID | string | Zeal `companyID` of Employer |
| business\_name | string | Business name of Employer |
Other [Shift Object](/reference/employee-checks/shifts/shift-object) fields.
***
## Returns
Doesn't return anything but rather POSTs a request with any changes in the [Shift Object](/reference/employee-checks/shifts/shift-object) to your webhook URL.
***
## Raw Content Example
```json theme={null}
[
{
"test": true,
"type": "update",
"shiftID": "123678098765",
"employeeID": "1234567890",
"employeeCheckID": "1097456820203947",
"status": "pending",
"first_name": "Erlich",
"last_name": "Bachman",
"time": "2023-05-17T04:00:00Z",
"metadata": {},
"wcc_code": null,
"workLocationID": 34567890,
"hourly": {
"hours": 7,
"wage": 22
},
"reimbursement": {
"amount": 15
},
"timestamp": "2024-01-21T21:29:42Z"
}
]
```
# Transaction Update Event
Source: https://docs.zeal.com/reference/webhooks/transaction-update-event
This endpoint specifies what will be sent to your Transaction Webhook.
This endpoint specifies what will be sent to your Transaction Webhook. Zeal POSTs a request containing a Transaction Object when it is is updated, namely a status change or new Transaction Event. You can update and test the webhook URL you want Zeal to hit on the 'API' Page of the Zeal Dashboard.
## Returns
Doesn't return anything but rather POSTs a request with a Transaction Object.
***
## Raw Content Example
```json Settled Transaction theme={null}
{
"test": false,
"transactionID": "a64f2bd0d7984ec9a999ff6ca92c567b",
"amount": 1018.05,
"status": "settled",
"method": "next_day_ach",
"source_instrument": {
"bankAccountID": null,
"last_four": null,
"paycardID": null,
"card_details": null,
"wire_details": null
},
"destination_instrument": {
"bankAccountID": "8b2a1073519a42f29ede3c29de573d16",
"last_four": "0089",
"paycardID": null,
"card_details": null
},
"transaction_type": "net_pay_credit",
"connection_type": "employee_check",
"connectionID": "d010afab12674659ac89705920c8a06d",
"traceID": null,
"retry": false,
"transaction_events": [
{
"transactionEventID": "f3b2a1c7e9d84b6a8c5f1d2e7a9b3c4d",
"timestamp": "2026-04-14T19:30:56.705Z",
"status": "processing",
"return_code": null,
"status_detail": null
},
{
"transactionEventID": "c8a4e1d7b2f93a6c5e1b7d9a3f2c4e8a",
"timestamp": "2026-04-14T19:30:57.205Z",
"status": "settled",
"return_code": null,
"status_detail": null
}
]
}
```
```json Returned transaction theme={null}
{
"test": false,
"transactionID": "4c9e1a7b2d6f8c3a5e1b9d7f2c6a8e4d",
"amount": 1162.38,
"status": "returned",
"method": "next_day_ach",
"source_instrument": {
"bankAccountID": "6f2a9c4e1b7d3a8f5c2e9b1d4a7c3f8e",
"last_four": "4321",
"paycardID": null,
"card_details": null,
"wire_details": null
},
"destination_instrument": {
"bankAccountID": "1e7b3c9f4a2d8e6c5b1f9a3d7c4e2b8a",
"last_four": "6789",
"paycardID": null,
"card_details": null
},
"transaction_type": "net_pay_credit",
"connection_type": "employee_check",
"connectionID": "9a3d7f1c4e8b2a6c5d1f9b3e7a2c4f6e",
"traceID": null,
"retry": false,
"transaction_events": [
{
"transactionEventID": "2d8f4a1c7e3b9c6a5f1d7e2b4c8a3f9e",
"timestamp": "2024-10-08T19:38:08.599Z",
"status": "processing",
"return_code": null,
"status_detail": null
},
{
"transactionEventID": "5e1a7c3d9f4b2a8e6c1d3f7b9a2c4e8f",
"timestamp": "2024-10-09T12:00:00.000Z",
"status": "settled",
"return_code": null,
"status_detail": null
},
{
"transactionEventID": "8c3f1a6d4e9b2c7a5f1d8b3e6a2c4f7d",
"timestamp": "2024-10-10T22:38:08.599Z",
"status": "returned",
"return_code": "R03",
"status_detail": "closed_bank_account"
}
]
}
```
# Webhook Event Overview
Source: https://docs.zeal.com/reference/webhooks/webhook-events
Overview of all webhook events Zeal sends - company and employee onboarding, contractor, and report status change - with payloads and security details.
Zeal sends webhook events to notify your platform of important state changes in real time. Rather than polling the API for updates, you configure a URL for each event type and Zeal delivers a POST request with a JSON payload whenever that event fires. This makes webhooks the preferred integration pattern for asynchronous workflows like employee onboarding completion or report generation.
You configure webhook URLs from the **Partner Dashboard** → **API page** → select the relevant event tab. Each event type has its own URL slot, so you can route events to different endpoints in your infrastructure if needed.
***
## Webhook Security
Every webhook request Zeal sends includes a `Puzzl-Signature` header. This header contains your Webhook Secret, shown in your Partner Dashboard under the API page. Verify it on every incoming request before processing the payload.
**Verification steps:**
1. Retrieve your Webhook Secret from the Partner Dashboard.
2. Compare the value of the `Puzzl-Signature` header on the incoming request to your Webhook Secret.
3. Reject the request if the values do not match.
Always verify the `Puzzl-Signature` header before trusting webhook payloads. Failing to do so may expose your system to spoofed events.
***
## Supported Webhook Events
### Company Onboarding Event
**When it fires:** When an employer completes the company onboarding flow through Zeal's white-label component or API.
**Use case:** Trigger downstream provisioning steps in your platform, such as unlocking payroll features or notifying an account manager.
**Sample payload:**
```json theme={null}
{
"event": "company_onboarding",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"onboarded": true,
"timestamp": "2024-01-15T10:30:00.000Z",
"data": {
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"legal_name": "Pied Piper Inc.",
"ein": "123456789",
"onboarded": true
}
}
```
***
### Employee Onboarding Event
**When it fires:** When an employee completes the Employee Onboarding flow through Zeal's white-label component. Zeal sends the event automatically once the employee's status is set to `onboarded`.
**Use case:** Update your platform's employee records, enable direct deposit, or trigger a welcome communication.
**Sample payload:**
```json theme={null}
{
"event": "employee_onboarding",
"employeeID": "emp_abc123",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"onboarded": true,
"timestamp": "2024-01-16T09:15:00.000Z",
"data": {
"employeeID": "emp_abc123",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com",
"onboarded": true
}
}
```
See [Employee Onboarding Event](/reference/webhooks/employee-onboarding-event) for the full field reference.
***
### Contractor Event
**When it fires:** When a 1099 contractor completes the Contractor Onboarding flow through Zeal's white-label component.
**Use case:** Update contractor records in your platform or trigger 1099 filing preparation.
**Sample payload:**
```json theme={null}
{
"event": "contractor_onboarding",
"contractorID": "ctr_def456",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"onboarded": true,
"timestamp": "2024-01-17T11:00:00.000Z",
"data": {
"contractorID": "ctr_def456",
"companyID": "fc235f012bae46aa8a082f357715bcfa",
"first_name": "Monica",
"last_name": "Hall",
"email": "monica@piedpiper.com",
"onboarded": true
}
}
```
See [Contractor Event](/reference/webhooks/contractor-event-webhook) for the full field reference.
***
### Job Queue Event (Report Status Change)
**When it fires:** When an asynchronous report job changes status - most importantly when it transitions to `"complete"` or `"failed"`.
**Use case:** Trigger your system to download the completed report instead of polling `GET /reports` in a loop.
**Sample payload:**
```json theme={null}
{
"event": "job_queue_status_change",
"job_id": "7g88a4e0-f2a0-4dc0-9a1c-215e083de5eb",
"status": "complete",
"timestamp": "2024-03-25T18:55:00.000Z",
"data": {
"job_id": "7g88a4e0-f2a0-4dc0-9a1c-215e083de5eb",
"status": "complete",
"payload": "https://api.zeal.com/reports/downloads/7g88a4e0-f2a0-4dc0-9a1c-215e083de5eb",
"report_format": "payroll_journal",
"company_id": "fc235f012bae46aa8a082f357715bcfa"
}
}
```
See [Report Status Webhook](/reference/webhooks/report-status-change-webhook) for the full field reference.
***
## Setting Up Webhook URLs
1. Log in to the **Partner Dashboard**.
2. Navigate to the **API** page.
3. Select the event tab for the webhook you want to configure (e.g., "Employee Onboarding Event").
4. Enter your endpoint URL in the field provided.
5. Save the configuration. Zeal will immediately begin delivering events to that URL.
You should respond to every webhook with an HTTP `200` status code. Zeal may retry delivery if your endpoint returns a non-2xx response.
# What are Zeal Webhooks?
Source: https://docs.zeal.com/reference/webhooks/what-are-zeal-webhooks
Webhooks are the way decisions and events are communicated by Zeal to you.
Webhooks are the way decisions and events are communicated by Zeal to you. Your webhook URLs can be viewed, edited, and tested on the API page of your Zeal dashboard. If adding or editing a webhook URL, please ensure the URL is correct and starts with a protocol secure `https` protocol.
Zeal signs the webhook events it sends to your endpoints by including a unique Webhook Secret (of String type) in every request's `Puzzl-Signature` header. This allows you to verify that the events were sent by Zeal. You can find your Webhook Secret and test your Webhooks on the API page of your Zeal dashboard. To verify a request from Zeal, check if the value from the `Puzzl-Signature` request's header matches your Webhook Secret.
# Create Work Location
Source: https://docs.zeal.com/reference/work-locations/create-work-location
openapi/zeal-api.json post /workLocations
Creates a Work Location for a specific company. You will receive an error if you try to create two work locations with the same combination of taxableLocationID and work_site_id.
# Get Work Locations
Source: https://docs.zeal.com/reference/work-locations/get-work-locations
openapi/zeal-api.json get /workLocations
Get a specific Work Location or all Work Locations in Zeal's system for a company.
# Update Work Location
Source: https://docs.zeal.com/reference/work-locations/update-work-location
openapi/zeal-api.json patch /workLocations
Update the name or work_site_id of an existing Work Location in Zeal's system.
# Work Location Object
Source: https://docs.zeal.com/reference/work-locations/work-location-object
The Work Location Object represents a Taxable Location Object with some extra metadata for reporting.
The Work Location Object represents a [Taxable Location Object](/reference/taxable-locations/taxable-location-object) with some extra metadata for reporting.
| attribute | type | description |
| :------------------ | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
| `workLocationID` | string | ID representing this Work Location |
| `companyID` | string | Unique identifier representing the company |
| `taxableLocationID` | string | ID representing this address that was generated from the [Resolve Taxable Location](/reference/taxable-locations/resolve-taxable-location) endpoint |
| `name` | string | Name of Work Location |
| `work_site_id` | string | Custom Work Site ID for your own reporting purposes |
```json theme={null}
{
"workLocationID": "531fece70b6d0b5d29c9f352",
"companyID": "1234567890",
"taxableLocationID": "609ffdf81a5f9c4c10b0c443",
"name": "Head Quarters",
"work_site_id": "HQ"
}
```
# Generate Company Login Link
Source: https://docs.zeal.com/reference/zeal-components/generate-company-login-link
openapi/zeal-api.json post /getAuthLink
Generate a link that automatically signs in a company and redirects them to their Zeal Company Dashboard, where they can manage and run payroll. This link can only be generated in production and expires exactly 7 days after generation.
# Generate Company Taxes Page link
Source: https://docs.zeal.com/reference/zeal-components/generate-company-taxes-page-link
openapi/zeal-api.json post /authLinks/taxes
Generate a link that automatically signs in a company and redirects them to their Taxes Dashboard, where they can view and edit taxes. This link can only be generated in production and expires exactly 7 days after generation.
# Generate Employee or Contractor Dashboard Link
Source: https://docs.zeal.com/reference/zeal-components/generate-employee-contractor-dashboard-link
openapi/zeal-api.json post /getAuthLink
Generate a link that automatically signs in an employee or contractor and redirects them to their Zeal worker dashboard. This link expires exactly 7 days after generation.
Generate a link that automatically signs in an employee or contractor and redirects them to their Zeal worker dashboard. This link (and dashboard) can be hosted on your custom domain. When a worker logs out of the dashboard, they will be redirected to the Base URL from your Settings page. This link expires exactly 7 days after generation.
This endpoint shares the `/getAuthLink` route with [Generate Company Login Link](/reference/zeal-components/generate-company-login-link). To generate a **worker** dashboard link, in addition to the parameters below also pass:
* **employeeID** (string) - ID of the employee to sign in
* **contractorID** (string) - ID of the contractor to sign in
* **use\_mfa** (boolean) - If true, MFA is required when accessing the worker dashboard
* **mfa\_methods** (string, enum: `email`, `sms`) - If not specified and `use_mfa` is true, both MFA options are shown
For worker dashboards, `embedded_page` accepts `dashboard-worker` (worker dashboard home), `profile-worker` (worker profile), or `wallet` (worker instant pay wallet) to embed a single page without the sidebar.
# Generate Reports Link
Source: https://docs.zeal.com/reference/zeal-components/generate-reports-link
openapi/zeal-api.json post /authLinks/reports
Generate a link that automatically signs in an employer and redirects them to their Zeal Reports Dashboard, where they can view all reports. This link can only be generated in production and expires exactly 7 days after generation.
# Get Contractor Payment Link
Source: https://docs.zeal.com/reference/zeal-components/get-contractor-payment-link
openapi/zeal-api.json get /paymentLink
Given the Company ID and Contractor Payment ID, Zeal returns an expirable, mobile-friendly link with the contractor payment details, including the ability to download the pay statement.
Given the Company ID and Contractor Payment ID, Zeal returns an expirable, mobile-friendly link with the contractor payment details, including the ability to download the pay statement. This link can be hosted on your custom domain in an iframe component and/or can be opened directly in a contractor's browser.
This link expires 24 hours after generation.
# Get Paystub/Employee Check Link
Source: https://docs.zeal.com/reference/zeal-components/get-paystub-link
openapi/zeal-api.json get /paystubLink
Given the Company ID and Employee Check ID, Zeal returns an expirable, mobile-friendly link with the employee check details, including the ability to download the paystub. This link expires 24 hours after generation.