Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.tryfinch.com/llms.txt

Use this file to discover all available pages before exploring further.

New to Finch webhooks? Start with Webhook Registration to set up your endpoint and get your secret, then see Webhook Verification to learn how to validate incoming webhooks.
Webhooks are not available on our legacy Free or Build plans. Upgrade to Starter, Pro, or Premier for access.

Webhook Payload Structure

Common payload fields

Each webhook event contains the following fields in the response body:
Field NameTypeDescription
company_idstring<uuid>Deprecated. Use connection_id instead.
account_idstring<uuid>Deprecated. Use connection_id instead.
connection_idstring<uuid>Unique Finch id representing the connection between a developer’s application and an employer’s provider. Created when an employer successfully authenticates through Finch Connect.
entity_idstring<uuid>Unique Finch id of the entity within the connection for which data has been updated. Present when the connection spans multiple entities; null otherwise.
event_typestringThe type of webhook being delivered.
dataobjectMore information about the associated event. The structure of this object will vary per event type.
Finch provides three general types of webhook events: account updates, job completions, and data changes.

Account Updates

Account update events contain information about account connections, such as when a connection has been established or when a connection has entered an error state. This type of webhook has the following unique schema:
Field NameTypeDescription
event_typestringAlways account.updated.
data.statusstringThe status of the account. This follows our standard connection status schema. Options are pending, processing, connected, reauth, error_permissions, error_no_account_setup, disconnected.
data.authentication_methodstringThe method of authentication used to connect this account. Options follow the standard Finch authentication types: credential, api_token, oauth, and assisted.
Example:
{
  "company_id": "720be419-0293-4d32-a707-32179b0827ab",
  "account_id": "fa872170-b49d-4fb5-aa39-fb1515db0925",
  "connection_id": "0057d3d2-fb43-4815-9f71-01ba4862d09f",
  "event_type": "account.updated",
  "data": {
    "status": "connected",
    "authentication_method": "assisted"
  },
  "entity_id": "61a9f5ba-95be-465d-a19b-34e19a07dd1c"
}

Job Completion

Job completion events fire when a job finishes running, whether the final state is a success or an error. Upon receiving a job.{job_type}.completed event, use the job_url in the payload to retrieve the job’s final status.
EventDescriptionValues
job.data_sync_all.completedEmitted for automated data sync jobs. Check status via the automated jobs endpoint.
job.w4_form_employee_sync.completedEmitted for automated W4 form sync jobs. Check status via the automated jobs endpoint.
job.initial_data_sync_*.succeededEmitted when an initial data sync completes successfully for the first time.initial_data_sync_org, initial_data_sync_payroll
job.benefit_*.completedEmitted for benefit-related jobs. Check status via the manual jobs endpoint.benefit_create, benefit_register, benefit_enroll, benefit_unenroll, benefit_update
This type of webhook has the following data schema:
Field NameTypeDescription
event_typestringFollows the schema job.{job_type}.completed. {job_type} can be any valid Finch job type such as data_sync_all, benefit_create, or benefit_enroll.
data.job_idstring<uuid>The id of the job which has completed.
data.job_urlstringThe url to query the result of the job.
Example:
{
  "company_id": "720be419-0293-4d32-a707-32179b0827ab",
  "account_id": "fa872170-b49d-4fb5-aa39-fb1515db0925",
  "connection_id": "0057d3d2-fb43-4815-9f71-01ba4862d09f",
  "event_type": "job.benefit_enroll.completed",
  "data": {
    "job_id": "10f249d5-c974-4ce3-979a-31164323a34f",
    "job_url": "https://api.tryfinch.com/jobs/10f249d5-c974-4ce3-979a-31164323a34f"
  },
  "entity_id": "282e6177-e2ec-4197-801d-7ab16c2b0c99"
}

Data Changes

Data change events fire when any data for a connection changes after Finch’s initial data sync. These could be created, updated, or deleted events on any of our endpoints. One event fires per changed record — for example, if 10 individuals are updated across Directory, Employment, or Individual, Finch sends 10 separate events. This type of event has the following schema:
Field NameTypeDescription
event_typestringFollows the schema {endpoint}.{created|updated|deleted}. {endpoint} can be any Finch endpoint such as company, directory, individual, etc. You can see the full up-to-date list of events by registering an endpoint in our developer dashboard.
dataobjectThe data object schema will change depending on the endpoint.
The possible data schemas per endpoint are as follows:
EndpointEvent typesdata fields
companycompany.updated onlynull
directorydirectory.created, directory.updated, directory.deletedindividual_id
employmentemployment.created, employment.updated, employment.deletedindividual_id
individualindividual.created, individual.updated, individual.deletedindividual_id
paymentpayment.created, payment.updated, payment.deletedpayment_id, pay_date
pay_statementpay_statement.created, pay_statement.updated, pay_statement.deletedpayment_id, individual_id
Examples:
Company
{
  "company_id": "720be419-0293-4d32-a707-32179b0827ab",
  "account_id": "fa872170-b49d-4fb5-aa39-fb1515db0925",
  "connection_id": "0057d3d2-fb43-4815-9f71-01ba4862d09f",
  "event_type": "company.updated",
  "data": null,
  "entity_id": "61a9f5ba-95be-465d-a19b-34e19a07dd1c"
}
Individual
{
  "company_id": "720be419-0293-4d32-a707-32179b0827ab",
  "account_id": "fa872170-b49d-4fb5-aa39-fb1515db0925",
  "connection_id": "0057d3d2-fb43-4815-9f71-01ba4862d09f",
  "event_type": "individual.updated",
  "data": {
    "individual_id": "9987ecd1-6c6e-4d97-81ae-4d0248dbdb3d"
  },
  "entity_id": "61a9f5ba-95be-465d-a19b-34e19a07dd1c"
}
Pay Statement
{
  "company_id": "720be419-0293-4d32-a707-32179b0827ab",
  "account_id": "fa872170-b49d-4fb5-aa39-fb1515db0925",
  "connection_id": "0057d3d2-fb43-4815-9f71-01ba4862d09f",
  "event_type": "pay_statement.created",
  "data": {
    "payment_id": "1c5e7bf2-94ce-4041-bf59-98e95677be21",
    "individual_id": "9987ecd1-6c6e-4d97-81ae-4d0248dbdb3d"
  },
  "entity_id": "61a9f5ba-95be-465d-a19b-34e19a07dd1c"
}
Note: One event is created for each pay statement object that has changed. For example, a new pay run for 20 individuals generates 20 unique pay statement events.

Supported Events

EventAutomatedAssisted
Account Updates
Job CompletionAll eventsBenefit jobs only
Data Changes

Required Events

The following events cover the core connection lifecycle. Any application integrating with Finch must handle them.
EventWhen to handleAction
account.updateddata.status is reauthPrompt the employer to re-authenticate via Finch Connect. See Reauthentication.
job.initial_data_sync_org.succeededInitial org data sync completesBegin reading org endpoints. Requests made before this event may return 202 or 500.
job.initial_data_sync_payroll.succeededInitial payroll data sync completesBegin reading payroll endpoints. Requests made before this event may return 202 or 500.
job.benefit_*.completedA benefit write job finishesCall Retrieve a Manual Job with data.job_id to check the outcome — the event fires on both success and failure. Required if your application writes deductions.

Webhook Registration

Webhook endpoints should use HTTPS and expect to receive POST requests with the following headers:
{
  "Content-Type": "application/json",
  "Finch-Event-Id": "msg_2SFMDibF3lmRw8DzX4t1JjiEZQl",
  "Finch-Signature": "v1,8rFENj/WpNAMx+Kh5R1NLQunmpaBx4vOntjJdbGKbvM=",
  "Finch-Timestamp": "1688737757"
}
You can create webhooks via the Finch Developer Dashboard. webhooksCreate.png After registering a webhook, Finch displays a webhook secret. This secret validates that incoming webhooks were sent by Finch. webhooksSecret The secret is displayed only once. Store it immediately. See the Webhook Verification section for more details.

Webhook Verification

Finch uses HMAC-SHA256 webhook verification. To verify a webhook using the Finch-Signature header:
  1. Extract the signature from the header. The Finch-Signature header consists of a list of signatures (where the signature content begins after “v1,” and is space delimited) to account for secret rotations; there may be multiple signatures present for cases where a secret was rotated. During the verification process, the signature must match at least one signature in the list to be considered valid.
v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= v1,bm9ldHUjKzFob2VudXRob2VodWUzMjRvdWVvdW9ldQo= v2,MzJsNDk4MzI0K2VvdSMjMTEjQEBAQDEyMzMzMzEyMwo=
  1. Generate the webhook signature
  • First, base64 decode the webhook secret to get the raw bytes.
  • Then, using the decoded webhook secret, hash the webhook content in the form {webhook_id}.{webhook_timestamp}.{body} where webhook_id is the Finch-Event-Id, webhook_timestamp is the Finch-Timestamp, and body is the raw request body. The signature is sensitive to any change in the body — do not modify it before verifying. If the computed signature does not match any signature in the Finch-Signature header, reject the webhook. Use a constant-time comparison to avoid timing attacks.
const crypto = require("crypto");

const signedContent = `${webhook_id}.${webhook_timestamp}.${body}`;
const SECRET = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH";

// base64 decode the secret before use
const secretBytes = new Buffer(SECRET, "base64");
const signature = crypto
  .createHmac("sha256", secretBytes)
  .update(signedContent)
  .digest("base64");
  1. Verify the webhook timestamp. If the signature is valid, check that the timestamp is within five minutes of the current time. If it is not, reject the webhook. Using outdated webhooks increases susceptibility to replay attacks.
The Finch Backend SDKs encapsulate all of this logic to simplify the webhook verification process.
import Finch from '@tryfinch/finch-api';
...

app.use('/webhooks/finch', bodyParser.text({ type: '_/_' }), function (req, res) {
const finch = new Finch();
const payload = finch.webhooks.unwrap(req.body, req.headers, process.env['FINCH_WEBHOOK_SECRET']); // env var used by default; explicit here.
console.log(payload);
res.json({ ok: true });
});

Testing Webhooks

You can send a test request to any webhook through the developer dashboard. Test webhooks The test webhook uses the same structure as data change webhooks, with event_type set to test.

Retry schedule

Upon failure, Finch retries according to the following schedule with exponential backoff:
  • Immediately
  • 5 seconds
  • 5 minutes
  • 30 minutes
  • 2 hours
If all retries are exhausted without a successful delivery, the event is dropped. Use the Finch API to fetch current data for any records you suspect may have been missed.

Best practices

Responding to Webhooks

To prevent unnecessary retries, receive and process webhook events in separate processes. Respond immediately with a 200 to indicate successful delivery, then process the event asynchronously.

Event Delivery and Ordering

  • You may occasionally receive the same webhook event more than once. Use the Finch-Event-Id to implement idempotent event processing.
  • Finch does not guarantee delivery of events in the order they happen. For example, you may receive an update event for an individual before a created event. You should also use the Finch API to occasionally fetch any missing data. For example, you can fetch an individual if you happen to receive an update event first.

Event Mapping

  • Each webhook includes a connection_id identifying the employer connection. Use it to route incoming events to the right employer in your system. For details on capturing and storing the connection_id, see Retrieve Access Token.
  • Each webhook also includes an entity_id for the specific entity within that connection. For multi-entity connections, the entity_id is required in subsequent API requests.