GuidesAPI ReferenceChangelog
Log In

Introduction

Webhooks allow you to subscribe to server-side notifications of events, like completing jobs and newly available data. Webhooks are helpful to optimize your Pinwheel integration.

Subscribing to Webhook Events

You can register a webhook endpoint by sending a request to create a webhook specifying the events to subscribe to with the enabled_events parameter. You should explicitly enumerate the events you'd like to subscribe to (e.g., ['direct_deposit_switch.added', 'income.added']). Webhook endpoints must be https:// so that the event payloads can be transmitted securely.

POST /v1/webhooks
Host: api.getpinwheel.com
Content-Type: application/json
x-api-secret: YOUR-API-SECRET

{
  "url": "https://your-domain.com/webhook_endpoint",
  "status": "active",
  "enabled_events": [
    "direct_deposit_switch.added",
    "income.added"
  ]
}

Webhook Pause Policy

Webhook endpoints that fail to return a successful response code (200 OK) for 30 consecutive days will be set to status: paused to avoid unnecessary delivery attempts.

Webhook Event Handling

Webhook events are delivered over HTTPS to the endpoint you registered. An example event is:

POST /webhook-endpoint
Host: app.yourdomain.com
Content-Type: application/json
x-pinwheel-signature: v2=36a0c8d2049601b11290ebcae3348f627cba32889ca5ac3c8ff7ece1fef1ad8f
x-pinwheel-webhook-id: 61788409-8314-4e89-9300-ae7b9d3ccff5
x-timestamp: 1609205925

{
  "event": "direct_deposit_switch.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    ...
  }
}

Verifying Pinwheel is the Sender

Pinwheel signs all webhook events it sends to your endpoints by including a signature in each event's x-pinwheel-signature header. You can use this signature to verify that the events were sent by Pinwheel, not by a third party. Learn more at Webhook Signature Verification.

Retry Policy

Pinwheel expects a response within 15 seconds from your endpoint. Pinwheel will redeliver a webhook event if your webhook endpoint returns a failure (5XX status codes or network issues). Up to 5 subsequent delivery attempts will be made with exponential backoff including jitter in the 15 minutes following the initial delivery attempt.

Handling Duplicate Events

The event_id request body parameter is unique for each webhook event. This can be used to guard against potential duplicate events and make your system idempotent. It can also be used to troubleshoot webhook event specific issues, so we recommend logging this identifier.

Webhook events are delivered with "at least once" guarantees, meaning that (rarely) the same webhook event will be delivered to your system multiple times.

Webhook Request Body

All webhook requests have a JSON body with the following parameters:

ParamTypeDescription
eventstringWebhook event, e.g., direct_deposit_switch.added.
event_idstringUnique ID for each webhook event.
payloadobjectPayload attributes vary based on event.

Webhook Request Headers

All webhook requests have the following headers:

HeaderTypeDescription
x-pinwheel-signaturestringSee Webhook Signature Verification.
x-pinwheel-webhook-idstringID of the webhook created via the POST /webhooks endpoint.
x-timestampintegerWhen the request was sent in Unix epoch time seconds.

Pending Webhook Job Outcomes

All job-associated webhook events include an outcome in the payload. The outcome represents the status of a job, and it can be either success, error, or pending. A pending status indicates that a job was unable to be completed on its first attempt and will be retried up to 24 hours after the initial attempt. A job with a pending status will transition to either an error or a success within the 24-hour window, and you will be notified with another webhook event.

Webhook Events

Account Webhook Events

account.added

User successfully logs into their payroll accounts. This webhook correlates to the onLogin callback.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when creating the Link token, if provided.
link_token_idstringUUID of the Link token used to initialize Link.
platform_idstringUUID of the payroll platform associated with this account.
platform_namestringThe name of the payroll platform associated with this account.
created_atstringISO 8601 timestamp of payroll account creation.
connectedbooleanIf set to true, you can retrieve new information for the account on a recurring basis.
monitoring_statusstringDescribes the automated ability of Pinwheel to retrieve new account information. See account.monitoring_status.updated for possible values.

Sample Webhook Event

{
  "event": "account.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "account_id": "03bbc20e-bc39-464a-b4dc-4b63ffb7213d",
    "end_user_id": "my_user_12345",
    "link_token_id": "7c4ac4be-4a0e-4468-ab26-c42b249b233b",
    "platform_id": "fce3eee0-285b-496f-9b36-30e976194736",
    "platform_name": "Justworks",
    "created_at": "2021-01-12T02:36:01.287148+00:00",
    "connected": true,
    "monitoring_status": "active"
  }
}

account.additional_connections_recommended

This webhook event evaluates the data retrieved from the payroll account to determine if another account (e.g., a T&A account) could provide additional data and provides a suggested action to take.

See Supplement Shifts with T&A Platforms for more information on how to work with the recommendations provided by this webhook event.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when creating the Link token, if provided.
additional_connectionsarrayA list of platform connection recommendations.
additional_connections.platform_typestringThe type of the platform this recommendation is for. Currently, only supports "time_and_attendance".
additional_connections.actionstringOne of none, login, search, or ask. See Supplement Shifts with T&A Platforms for more information on how to work with these recommendations.
additional_connections.platform_id (optional)stringUUID of the recommended platform, if we recommended connecting to it (i.e., action is login).
link_token_idstringUUID of the Link token used to initialize Link.

Sample Webhook Event

{
  "event": "account.additional_connections_recommended",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "account_id": "03bbc20e-bc39-464a-b4dc-4b63ffb7213d",
    "end_user_id": "my_user_12345",
    "link_token_id": "158dc949-84a3-4c81-bf7f-2977b4d70048",
    "additional_connections": [
        {
            "platform_type": "time_and_attendance",
            "action": "login",
            "platform_id": "7ceec993-c958-4b90-b419-fda2506b612d"
        }
    ]
  }
}

account.monitoring_status.updated

Pinwheel's ability to monitor a payroll account has changed (i.e. DDA and I&E).

Several monitoring statuses are possible:

monitoring_statusDescription
activePinwheel is monitoring for data changes daily.
degradedPinwheel is trying to monitor but seeing spurious errors and may be unable to return data for the time being. You may want to use this to inform users about laggy data.
user_action_requiredYou need to use On Demand Updates to have a user re-complete the login process.
unavailablePinwheel doesn’t support monitoring for this account.
customer_disabledYou used POST /v1/accounts/{id}/disable_monitoring to manually turn off monitoring.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the account, if provided.
updated_atstringISO 8601 timestamp of when Pinwheel updated the monitoring_status for this account.
current_monitoring_statusstringThe latest monitoring status for the account. See the table above for a set of possible values.

Sample Webhook Event

{
  "event": "account.monitoring_status.updated",
  "event_id": "5a141122-4235-4fa1-bd76-0123456780b0",
  "payload": {
    "current_monitoring_status": "active",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "updated_at": "2021-01-12T02:36:01.287148+00:00"
  }
}

Direct Deposit Webhook Events

Direct Deposit webhook events will notify you when new direct deposit allocation data is available for a payroll account or a direct deposit job completed.

direct_deposit_allocations.added

Direct deposit allocations data is now available for the payroll account.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "direct_deposit_allocations.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_allocations",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success"
  }
}

direct_deposit_switch.added

A direct_deposit_switch job to add a new direct deposit allocation completed.

Payload Schema
Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
params (optional)objectParameters of the job, if applicable.
params.actionstringIndicates whether the direct_deposit_switch was a full_switch or a partial_switch.
params.allocation (optional)objectThe allocation that was created/updated during a direct_deposit_switch. Only present when params.action is partial_switch
params.allocation.type (optional)stringIndicates whether this is a remainder, amount or percentage allocation. Will be set if params.action is partial_switch.
params.allocation.value (optional)integerThe value (if any) for this allocation. Will be set if the type is percentage or amount.
params.allocation.target.account_name (optional)stringThe account name (if any) for this allocation. We recommending including name during link token creation if you send multiple accounts.
params.allocation.target.account_typestringThe account type for this allocation. Will be either checking or savings.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.
Sample Webhook Events
  • A partial amount switch creates a fixed-amount allocation on the payroll account.
  • A partial percentage switch creates a percentage-based allocation on the payroll account.
  • A remainder switch replaces the existing remainder allocation on a payroll account and leaves existing allocations unaffected.
{
  "event": "direct_deposit_switch.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_switch",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "action": "partial_switch",
      "allocation": {
        "type": "amount",
        "value": 5400,
        "target": {
          "account_name": "My Checking Account",
          "account_type": "checking"
        }
      }
    }
  }
}
{
  "event": "direct_deposit_switch.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_switch",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "action": "partial_switch",
      "allocation": {
        "type": "percentage",
        "value": 33,
        "target": {
          "account_name": "My Checking Account",
          "account_type": "checking"
        }
      }
    }
  }
}
{
  "event": "direct_deposit_switch.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_switch",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "action": "partial_switch",
      "allocation": {
        "type": "remainder",
        "target": {
          "account_name": "My Checking Account",
          "account_type": "checking"
        }
      }
    }
  }
}
{
  "event": "direct_deposit_switch.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_switch",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "action": "full_switch",
      "allocation": {
        "target": {
          "account_name": "My Checking Account",
          "account_type": "checking"
        }
      }
    }
  }
}

Income & Employment Webhooks

Income and Employment webhook events will notify you when the data for a given product is ready to be retrieved. The payload is summary information, not the data itself. After receiving a webhook event, call the corresponding endpoint to retrieve the account data.

employment.added

Employment data for the payroll account is available. Use account_id in the payload to query the Get Employment endpoint to fetch the data.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
params (optional)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "employment.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "employment",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success"
  }
}

identity.added

Identity data for the payroll account is available. Use account_id in the payload to query the Get Identity endpoint to fetch the data.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
params (optional)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "identity.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "identity",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success"
  }
}

income.added

Income data for the payroll account is available. Use account_id in the payload to query the Get Income endpoint to fetch the data.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
params (optional)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "income.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "income",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success"
  }
}

paystubs.added

A set of Paystubs are available. The params describes which paystubs. Use account_id in the payload to query the Get Paystub endpoint to fetch them.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
paramsobjectParameters of the job, if applicable.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
addedarrayA list of objects specifying IDs of the new paystubs that were added to the payroll account.
deletedarrayA list of objects specifying IDs of the old paystubs that were removed from the payroll account.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "paystubs.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "paystubs",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "added": [{"id": "dbff9830-55ce-4aa5-82f1-e04f196da041"}],
    "deleted": [{"id": "57043868-6fb3-47e8-a2b7-c993bd023f25"}],
    "params": {
      "from_pay_date": "2020-10-01",
      "to_pay_date": "2020-12-31",
      "count": 6,
      "sync_status": "in_progress",
    }
  }
}

Paystubs Sync Events

A paystubs sync event will trigger as soon as the relevant data has been retrieved. If there isn't enough data to meet the 30d or 90d threshold, that event will be skipped. The sync status events are:

  • paystubs.seven_days_synced: Triggered when 7 days of paystubs have been collected
  • paystubs.thirty_days_synced: Triggered when 30 days of paystubs have been collected
  • paystubs.ninety_days_synced: Triggered when 90 days of paystubs have been collected
  • paystubs.fully_synced: Triggered when all available paystubs have been collected
Payload Schema
Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
paramsobjectParameters of the job, if applicable.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.
Sample Webhook Events
{
  "event": "paystubs.seven_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "paystubs",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "from_pay_date": "2020-12-15",
      "to_pay_date": "2020-12-21",
      "count": 1
    }
  }
}
{
  "event": "paystubs.thirty_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "paystubs",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "from_pay_date": "2020-11-20",
      "to_pay_date": "2020-12-14",
      "count": 2
    }
  }
}
{
  "event": "paystubs.ninety_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "paystubs",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "from_pay_date": "2020-08-15",
      "to_pay_date": "2020-11-29",
      "count": 6
    }
  }
}
{
  "event": "paystubs.fully_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "paystubs",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "from_pay_date": "2020-08-01",
      "to_pay_date": "2020-08-14",
      "count": 2
    }
  }
}

shifts.added

A set of Shifts are available. The params describes the number of shifts. Use account_id in the payload to query the List Shifts endpoint to fetch them.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
params (optional)objectInput parameters to the job, if applicable.
error_code (optional)stringOn error, a string describing the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
addedarrayA list of objects specifying IDs of the new shifts that were added to the payroll account.
deletedarrayA list of objects specifying IDs of the old shifts that were removed from the payroll account.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
  "event": "shifts.added",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "added": [{"id": "dbff9830-55ce-4aa5-82f1-e04f196da041"}],
    "deleted": [{"id": "57043868-6fb3-47e8-a2b7-c993bd023f25"}],
    "params": {
      "count": 14,
      "sync_status": "complete",
    }
  }
}

Shifts Sync Events

A shifts sync event will trigger as soon as the relevant data has been retrieved. If there isn't enough data to meet the 30d or 90d threshold, that event will be skipped. The sync status events are:

  • shifts.seven_days_synced: Triggered when 7 days of shifts have been collected
  • shifts.thirty_days_synced: Triggered when 30 days of shifts have been collected
  • shifts.ninety_days_synced: Triggered when 90 days of shifts have been collected
  • shifts.fully_synced: Triggered when all available shifts have been collected

Note that only 90 days of data are collected for shifts. Thus, shifts.ninety_days_synced and shifts.fully_synced will trigger at the same time.

Payload Schema
Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
paramsobjectParameters of the job, if applicable.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.
Sample Webhook Event
{
  "event": "shifts.seven_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 6
    }
  }
}
{
  "event": "shifts.thirty_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 20
    }
  }
}
{
  "event": "shifts.ninety_days_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 20
    }
  }
}
{
  "event": "shifts.fully_synced",
  "event_id": "5a141122-4235-4fa1-bd76-0628573880b0",
  "payload":{
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
    "end_user_id": "my_user_12345",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 20
    }
  }
}

Tax Forms Webhooks

Tax forms webhook events will notify you when new tax forms data is available for a payroll account or a tax forms job completed.

tax_forms.added

Tax forms data for the payroll account is available. Use account_id in the payload to query the Get Tax Form endpoint to fetch the data.

Payload Schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
end_user_idstringThe user identifier you specified when the user initially connected to the payroll account, if provided.
outcomestringThe outcome of the job, either success, error, or pending. If pending you will receive another webhook with outcome as success or error within 24 hours.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
params (optional)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.
namestringName of the job.
link_token_idstringUUID of Link token used to initialize Link, or an undefined link token if triggered by a refresh job (such as from DDA Monitoring). You should use account_id as the main identifier.
addedarrayA list of objects specifying ID, year, and form type of the new tax forms that were added to the payroll account.
deletedarrayA list of objects specifying ID, year, and form type of the old tax forms that were removed from the payroll account.
idstringDeprecated. UUID of the job. You should use account_id as the main identifier.

Sample Webhook Event

{
    "event": "tax_forms.added",
    "event_id": "9bb2d0cd-9f54-4829-a6c2-a48b0cd18b6d",
    "payload": {
        "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
        "end_user_id": "01234",
        "link_token_id": "f2b2cc6e-b53c-4175-9319-acfc3f39f9f2",
        "name": "tax_forms",
        "timestamp": "2021-01-12T02:36:01.287148+00:00",
        "outcome": "success",
        "added": [{
            "id": "b0e92f7b-c0b2-4418-a34d-3f316ca45c84",
            "year": 2022,
            "form_type": "W-2"
        }],
        "deleted": [{
            "id": "57043868-6fb3-47e8-a2b7-c993bd023f25",
            "year": 2001,
            "form_type": "1099-K"
        }]
    }
}

Earnings Stream Webhooks

Earnings Stream webhook events will notify you when a newer version of the Earnings Stream is available for a user.

earnings_stream.payouts.refreshed

Payouts for a user's earnings stream have been refreshed. Use end_user_id in the payload to query the Get Earnings Stream Payouts to fetch the most up-to-date payouts data.

We’ll send this webhook event:

  • After your user connects an account with Link or performs an On Demand Update
  • Whenever Monitoring detects a change to the underlying information in Earnings Stream.

The webhook event will include metadata about the Earnings Stream, indicating which components are available or unavailable. If unavailable it will include an unavailable_reason summarizing why.

Payload Schema

Payload ParamTypeDescription
end_user_idstringThe user identifier you provided in the link token to connect the account.
refreshed_atstringISO 8601 timestamp of when the data underlying the earnings stream was most recently checked for changes.
updated_atstringISO 8601 timestamp of when the earnings stream most recently had a data change (e.g., the user worked another shift so a new accrued earning was recorded).
availabilityobjectSee child attributes for details.
availability.payouts_estimatedobjectSee child attributes for details.
availability.payouts_estimated.earnings_accruedobjectAvailability of accrued earnings for estimated payouts. See Availability Schema below for object structure.
availability.payouts_processedobjectSee child attributes for details.
availability.payouts_processed.earnings_accruedobjectAvailability of accrued earnings for processed payouts. See Availability Schema below for object structure.
availability.payouts_processed.earnings_unknownobjectAvailability of unknown earnings for processed payouts. See Availability Schema below for object structure.
Availability Schema
ParameterTypeDescription
statusstringEither available, if the class of data is present in the Earnings Stream, or unavailable, if the data can not be included.
unavailable_reason (optional)stringOn unavailable, provides an explanation for why the data is not present. See the table below for possible values. null if status = available.
Unavailable Reasons
Unavailable ReasonDescription
missing_in_period_shifts_dataNo shifts were found for the current pay period i.e. shifts worked after the most recent paystub's pay period end.
missing_paystubs_dataNo paystubs were found for this end user.
missing_income_dataNo income data was found for this end user.
invalid_in_period_shifts_dataShifts were found for the current pay period, however, they failed data validation
invalid_paystubs_dataPaystubs were found for the end user, however, they failed data validation
invalid_income_dataIncome data was found for the end user, however, it failed data validation
paystubs_data_not_supported_by_platformPlatform does not support paystubs data
shifts_data_not_supported_by_platformPlatform does not support shifts data
income_data_not_supported_by_platformPlatform does not support income data

All of the above reasons can be caused by platform-specific or user-specific problems. For example, the platform lacks support for paystubs data or the user is a new employee and hasn't been issued their first paystub yet.

We may add additional unavailable reasons without releasing a new API version. Make sure to handle a default other case if parsing these as enums.

Sample Webhook Event

{
    "event": "earnings_stream.payouts.refreshed",
    "event_id": "e9d5660b-52cc-4b66-adba-67eed17447fe",
    "payload": {
        "end_user_id": "john_doe_1234",
        "updated_at": "2022-01-01T00:00:00+0000",
        "refreshed_at": "2022-01-02T00:00:00+0000",
        "availability": {
            "payouts_estimated": {"earnings_accrued": {"status": "available", "unavailable_reason": null}},
            "payouts_processed": {
                "earnings_accrued": {"status": "available", "unavailable_reason": null},
                "earnings_unknown": {"status": "available", "unavailable_reason": null},
            },
        },
    }
}

Please contact [email protected] for access to our Developer Dashboard.


Did this page help you?