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_payment.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 Event Handling

Webhook events are delivered over HTTPS to the endpoint you registered. An example notification 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_payment.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.

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_payment.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 product specific webhook events (Direct Deposit and Income and Employment) 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 connects logs into their payroll accounts. This webhook correlates to the onLogin callback.

Payload schema

Payload ParamTypeDescription
account_idstringUUID of the payroll account.
link_token_idstringUUID of the Link token used to initialize Link.
platform_idstringUUID of the payroll platform associated with this account.
created_atstringISO 8601 timestamp of payroll account creation.

Sample webhook event

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

Direct Deposit Webhook Events

Direct Deposit webhook events will notify you when a Direct Deposit job has completed. The payload is the Jobs object that initiated the change.

direct_deposit_allocations.added

Direct deposit allocations data for the job is available.

Payload schema

Payload ParamTypeDescription
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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.
timestampstringISO 8601 timestamp of job completion.

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",
    "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_payment.added

A direct_deposit_payment job to add new direct deposit allocation completed.

Payload schema

Payload ParamTypeDescription
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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)objectParameters of the job, if applicable.
params.amount (optional)integerThe amount to allocate per paycheck in pennies, if applicable.
timestampstringISO 8601 timestamp of job completion.

Sample webhook event

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

direct_deposit_switch.added

A direct_deposit_switch job to add new direct deposit allocation completed. When a user does a full switch amount will be null.

Payload schema

Payload ParamTypeDescription
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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)objectParameters of the job, if applicable.
params.amount (optional)integerThe amount to allocate per paycheck in pennies, if applicable.
timestampstringISO 8601 timestamp of job completion.

Sample webhook event

{
  "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",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "direct_deposit_switch",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "amount": null
    }
  }
}

Income and Employment Webhook Events

Income and Employment webhook events will notify you when the data for a given product is ready to be retrieved. The payload is the Job object that initiated the change, 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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.

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",
    "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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.

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",
    "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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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)objectParameters of the job, if applicable.
timestampstringISO 8601 timestamp of job completion.

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",
    "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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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.
timestampstringISO 8601 timestamp of job completion.

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",
    "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-10-01",
      "to_pay_date": "2020-12-31",
      "count": 6
    }
  }
}

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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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.
timestampstringISO 8601 timestamp of job completion.
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",
    "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-31",
      "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",
    "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-15",
      "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",
    "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-14",
      "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",
    "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-15",
      "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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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.
timestampstringISO 8601 timestamp of job completion.

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",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 14
    }
  }
}

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
idstringUUID of the job.
account_idstringUUID of the payroll account.
error_code (optional)stringOn error, a string describing the error.
error_type (optional)stringOn error, a high level classification of the error.
link_token_idstringUUID of Link token used to initialize Link.
namestringName of the job.
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.
timestampstringISO 8601 timestamp of job completion.
Sample webhook events
{
  "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",
    "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",
    "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",
    "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",
    "link_token_id": "4787acbc-11cf-4db3-998c-5ea7c4feebcd",
    "name": "shifts",
    "timestamp": "2021-01-12T02:36:01.287148+00:00",
    "outcome": "success",
    "params": {
      "count": 20
    }
  }
}

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


Did this page help you?