# Get Plan Source: https://developer.tryfinch.com/api-reference/benefits/get-plan get /employer/plans/{plan_id} **Beta:** This endpoint is in beta and may change. Read a single benefit plan by its Finch ID. # Get Dependents Source: https://developer.tryfinch.com/api-reference/benefits/get-plan-dependents post /employer/plans-dependents **Beta:** This endpoint is in beta and may change. Read dependents by Finch ID. A maximum of 50 dependents can be requested at once. # Get Enrollments Source: https://developer.tryfinch.com/api-reference/benefits/get-plan-enrollments post /employer/plans-enrollments **Beta:** This endpoint is in beta and may change. Read enrollments by Finch ID. A maximum of 50 enrollments can be requested at once. # List Dependents Source: https://developer.tryfinch.com/api-reference/benefits/list-plan-dependents get /employer/plans-dependents **Beta:** This endpoint is in beta and may change. Read the dependents covered under the benefit plans of the company, including their coverage and enrollments. # List Enrollments Source: https://developer.tryfinch.com/api-reference/benefits/list-plan-enrollments get /employer/plans-enrollments **Beta:** This endpoint is in beta and may change. Read individuals' enrollments in the company's benefit plans, including coverage dates and contributions. # List Plans Source: https://developer.tryfinch.com/api-reference/benefits/list-plans get /employer/plans **Beta:** This endpoint is in beta and may change. Read the benefit plans offered by the company, including carrier, coverage tiers, and deduction codes. # Create a new connect session Source: https://developer.tryfinch.com/api-reference/connect/new-session post /connect/sessions Create a new connect session for an employer NOTE: The connect session uses Basic Auth; in the sample request above use `client_id` as the username and `client_secret` as a password. For example: `Authorization: Basic ` # Create a new Connect session for reauthentication Source: https://developer.tryfinch.com/api-reference/connect/reauthenticate-session post /connect/sessions/reauthenticate Create a new Connect session for reauthenticating an existing connection NOTE: The connect session uses Basic Auth; in the sample request above use `client_id` as the username and `client_secret` as a password. For example: `Authorization: Basic ` # Create Deduction Source: https://developer.tryfinch.com/api-reference/deductions/create-deduction post /employer/benefits Creates a new company-wide deduction or contribution. Please use the `/providers` endpoint to view available types for each provider. **Availability: Automated and Assisted providers** Employer Match capabilities are currently in Beta. Please reach out if you are interested in gaining early access. If the same request is made more than once with the same `type`, `frequency` and `description`, a new item will not be created. Finch will instead return the `benefit_id` of the existing item. Latencies may vary depending on whether the provider is Automated or Assisted - new items will be created within minutes for Automated providers and within the 2 business day SLA for Assisted providers. # Enroll Individuals in Deductions Source: https://developer.tryfinch.com/api-reference/deductions/enroll-individuals-in-deductions post /employer/benefits/{benefit_id}/individuals Enroll an individual into a deduction or contribution. This is an overwrite operation. If the employee is already enrolled, the enrollment amounts will be adjusted. Making the same request multiple times will not create new enrollments, but will continue to set the state of the existing enrollment. **Availability: Automated and Assisted providers** This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider and number of benefits. Making changes to an individual's deductions may have tax consequences based on IRS regulations. Please consult a tax expert to ensure all changes being made to the system are compliant with local, state, and federal law. The request body is a **bare array** of enrollment objects — `[ { "individual_id": …, "configuration": … } ]`. Do not wrap it in an object: sending `{ "items": [ … ] }` returns `400 Expected array but received object`. In the schema below, the `items.` prefix labels each element of the array, not a top-level `items` field. ### Enrollment Bodies Enrollment bodies have a common format for each benefit type, with a different `configuration` schema based on the benefit type. The configurations for each type are outlined below. These are general configurations and may vary per provider. Please use the `/provider` endpoint to view provider specific supported configurations. #### Retirement Benefits Includes 401(k), Roth 401(k), 403(b), Roth 403(b), 457, Roth 457, and Simple IRA | Field | Type | Description | | ----------------------------- | ---------------------- | --------------------------------------------------------------------- | | `employee_deduction.type` | `string` | Deduction Type (`fixed` or `percent`) | | `employee_deduction.amount` | `integer` | Deduction amount in cents (if `fixed`) or basis points (if `percent`) | | `company_contribution.type` | `string` | Contribution Type (`fixed` or `percent`) | | `company_contribution.amount` | `integer` | Contribution amount in cents (if `fixed`) or basis points | | `catch_up` | `boolean` | Whether to enable catch up for this individual | | `annual_maximum` | `integer` (`nullable`) | The annual maximum in cents for this individual | | `effective_date`\* | `string` (`nullable`) | The date which the benefit should take effect by (`mm/dd/yyyy`) | #### HSA | Field | Type | Description | | ----------------------------- | ---------------------- | --------------------------------------------------------------------- | | `employee_deduction.type` | `string` | Deduction Type (`fixed` or `percent`) | | `employee_deduction.amount` | `integer` | Deduction amount in cents (if `fixed`) or basis points (if `percent`) | | `company_contribution.type` | `string` | Contribution Type (`fixed` or `percent`) | | `company_contribution.amount` | `integer` | Contribution amount in cents (if `fixed`) or basis points | | `catch_up` | `boolean` | Whether to enable catch up for this individual | | `annual_maximum` | `integer` (`nullable`) | The annual maximum in cents for this individual | | `annual_contribution_limit` | `string` (`nullable`) | Whether HSA is applied towards `individual` or `family` | | `effective_date`\* | `string` (`nullable`) | The date which the benefit should take effect by (`mm/dd/yyyy`) | #### Section 125 Benefits, FSA, Custom Benefits | Field | Type | Description | | ----------------------------- | --------------------- | --------------------------------------------------------------------- | | `employee_deduction.type` | `string` | Deduction Type (`fixed` or `percent`) | | `employee_deduction.amount` | `integer` | Deduction amount in cents (if `fixed`) or basis points (if `percent`) | | `company_contribution.type` | `string` | Contribution Type (`fixed` or `percent`) | | `company_contribution.amount` | `integer` | Contribution amount in cents (if `fixed`) or basis points | | `effective_date`\* | `string` (`nullable`) | The date which the benefit should take effect by (`mm/dd/yyyy`) | * Note: `effective_date`s that are undefined or in the past will default to the date the request was made. We recommend grouping enrollments by `effective_date` for a request. If multiple distinct `effective_date`s are included, the job will be in pending status until the latest `effective_date` enrollment is processed. Sandbox integrations do not currently support multiple distinct `effective_date`s within the same request. # Get All Deductions Source: https://developer.tryfinch.com/api-reference/deductions/get-all-deductions get /employer/benefits List all company-wide deductions and contributions. **Availability: Automated providers only** Employer Match capabilities are currently in Beta. Please reach out if you are interested in gaining early access. This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider and number of items. This endpoint returns a **bare array** of benefits — `[ { … } ]` — not an object. In the schema below, the `items.` prefix labels each element of the array, not a top-level `items` field. # Get Deduction Source: https://developer.tryfinch.com/api-reference/deductions/get-deduction get /employer/benefits/{benefit_id} Lists deductions and contributions information for a given item **Availability: Automated providers only.** Employer Match capabilities are currently in Beta. Please reach out if you are interested in gaining early access. This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider. # Get Deductions for Individuals Source: https://developer.tryfinch.com/api-reference/deductions/get-deductions-for-individuals get /employer/benefits/{benefit_id}/individuals Get enrollment information for the given individuals. **Availability: Automated providers only** This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider and number of benefits. This endpoint returns a **bare array** — `[ { … } ]` — not an object. In the schema below, the `items.` prefix labels each element of the array, not a top-level `items` field. # Get Enrolled Individuals Source: https://developer.tryfinch.com/api-reference/deductions/get-enrolled-individuals get /employer/benefits/{benefit_id}/enrolled Lists individuals currently enrolled in a given deduction. **Availability: Automated providers only** This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider and number of benefits. # Register Deduction Source: https://developer.tryfinch.com/api-reference/deductions/register-deduction post /employer/benefits/register Register existing benefits from the customer on the provider, on Finch's end. Please use the `/provider` endpoint to view available types for each provider. **Availability: Assisted providers only** # Unenroll Individuals from Deductions Source: https://developer.tryfinch.com/api-reference/deductions/unenroll-individuals-from-deductions delete /employer/benefits/{benefit_id}/individuals Unenroll individuals from a deduction or contribution **Availability: Automated and Assisted providers** This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider. # Update Deduction Source: https://developer.tryfinch.com/api-reference/deductions/update-deduction post /employer/benefits/{benefit_id} Updates an existing company-wide deduction or contribution **Availability: Automated and Assisted providers** This is a live request to the provider. Latencies may vary from seconds to minutes depending on the provider. # Handling API Responses Source: https://developer.tryfinch.com/api-reference/development-guides/Handling-API-Responses Handle null values and 202 responses from the Finch API — why each occurs and the retry, backoff, and null-check behavior your application should implement. ## Null Values Finch returns `null` for a field on a record when: 1. the employment system doesn't support the field, 2. the employment system supports the field but the payroll administrator hasn't filled in the data, or 3. Finch can't infer a reasonable value (for example, the categorization of a tax). Null-ness is per record, not per field — one individual may have a value where another doesn't. Check a field's value for `null` before operating on it — for example, before calling a string method or accessing a nested property — rather than assuming every record has a value. Check a field's value for `null` before operating on it. Don't assume every record has a value just because other records do. ## 202 Response Codes Requests to the Finch API can return a [`202 Accepted`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202) response. This means the connection exists but the data isn't available yet — common for async operations. Once the data is available, Finch stops returning `202` for that request. Requests that can return a `202` response include: * [Assisted Connect](/integrations/providers#integration-types), including [Assisted Deductions](/implementation-guide/API-Calls/Write-Data#assisted-deductions) * [Pay statements](/developer-resources/Data-Syncs#pay-statements) that exist but haven't been fetched yet * [Authentication fallback](/implementation-guide/Integration-Preparation/Configure-Auth-Methods#set-up-authentication-fallback) Handle a `202` response by: * **Retrying** the request after a delay. For assisted connections, the SLA for the first data sync is 14 days. * **Backing off** — increase the delay between retries if the response keeps returning `202`. * Not processing the response body as data until you receive a successful response. Examples of 202 Responses: ```json theme={null} { "code": 202, "name": "accepted", "finch_code": "data_sync_in_progress", "message": "The pay statements for this payment are being fetched. Please check back later." } { "code": 202, "name": "authorization_pending", "finch_code": "pending", "message": "Authorization to this company's data is pending" } ``` See [Testing assisted integrations](/implementation-guide/Test/Finch-Sandbox#testing-assisted-integrations) to simulate the pending state that produces a `202` response in the Finch Sandbox. # Headers Source: https://developer.tryfinch.com/api-reference/development-guides/Headers ## Request Headers Every request to Finch's API requires the following headers— | Header | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | Bearer authorization header, which is formed by concatenating the word “Bearer” with the access token, separated by a space. | | `Finch-API-Version` | Header used to specify the version for a given API request. Current version is **2020-09-17**. | *** ## Response Headers Finch's additional response headers provide information about the data contained in responses. | Header | Description | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Finch-Request-Id` | Each response from Finch's API has a unique request identifier. If you need to contact us about a specific request, providing the request identifier will ensure the fastest possible resolution. | | `Finch-Data-Retrieved` | The date/time in ISO-8601 format that the data was retrieved from the employment system. | | `Finch-Last-Attempted-Update-Date` | The date/time in ISO-8601 format that Finch last attempted to update this data. | | `Finch-Last-Attempted-Update-Result` | The result of Finch's last attempted update. Possible values:
`success`: the last attempt succeeded
`error`: the last attempt errored
`partial_error`: (batch requests only) the last attempt succeeded for some items in the batch and failed for others. | # Permissions Source: https://developer.tryfinch.com/api-reference/development-guides/Permissions Each Finch `access_token` can only make API calls to endpoints the end-user has granted an application permission to. Permissions are specified by the `product` parameter when launching Connect. Valid permissions are— | Permission | Endpoints | Description | | --------------- | ----------------------------------------------- | ------------------------------------------------------------------ | | `company` | `/employer/company` | Read basic company data | | `directory` | `/employer/directory` | Read company directory and organization structure | | `individual` | `/employer/individual` | Read individual data, excluding income and employment data | | `ssn` | `/employer/individual` | Read SSN for individuals. | | `employment` | `/employer/employment` | Read individual employment and income data | | `payment` | `/employer/payment`
`/employer/pay-groups` | Read payroll and contractor related payments by the company | | `pay_statement` | `/employer/pay-statement` | Read detailed pay statements for each individual | | `benefits` | `/employer/benefits/*` | Create and manage benefits and benefit enrollment within a company | | `documents` | `/employer/documents/*` | Read company documents | # Rate Limits Source: https://developer.tryfinch.com/api-reference/development-guides/Rate-Limits In this guide, you'll learn about total rate limits for Finch, rate limits for specific IP Addresses, and how to handle rate limit errors. Finch's rate limits work on a per-endpoint basis for applications, and we refer to each distinct endpoint as a unique `product`. Rate limits are summed on a rolling 60-second basis for each unique `product`. This is commonly referred to as a Sliding or Rolling Window rate limit. **Access Token rate limits** Finch previously enforced rate limits at the access token level but this is no longer the case as of August 2023. You can think of a `product` rate limit like a "bucket". Therefore, when a request is made to a `product` (which corresponds directly to an API endpoint), a single gallon of water is added to that endpoint's bucket, thus starting that bucket's 60-second time-to-live (TTL) timer. After the product's rate limit is reset after 60 seconds, the first request to that `product` starts the 60-second TTL again. *** ## Application Rate Limits A Finch application has its own rate limits and all access tokens associated with the application will be subject to the application's rate limits. For application-level rate limits, each `product` manages a bucket simultaneously counting all requests across all access tokens created by that application. Multiple access tokens can be created from a single Finch application as more employers are connected. (A Finch application corresponds to a unique `client_id`. You may have several `client_id`s if you use a development or sandbox application in addition to production). | Product | Max requests initiated per minute | | -------------------- | --------------------------------- | | `company` | 20 | | `directory` | 20 | | `documents` | 20 | | `individual` | 20 | | `employment` | 20 | | `pay-statement-item` | 20 | | `payment` | 12 | | `pay-groups` | 12 | | `pay-statement` | 12 | If an application rate limit is encountered, it will contain the `finch_code`: [finch\_application\_rl](/api-reference/development-guides/errors/Error-Types#error-types-1) in the response body. ```json theme={null} // HTTP 429 response body for application rate limit exceeded { "statusCode": 429, "status": 429, "code”: 429, "message": "Too many requests for token", "name": "rate_limit_exceeded_error", "finch_code": "finch_application_rl" } ``` ## IP Address Rate Limits Finch also enforces individual IP Address rate limits. An IP address is a unique address that identifies a device on the internet or a local network. If the number of `max requests` are sent from the same IP Address within the `duration` time set, a `penalty` is enforced. No more requests are allowed once the penalty is enforced. Once the penalty duration is complete, requests will be accepted again. | Type | Max requests | Duration | Penalty | | ----- | ------------ | --------- | ---------- | | `API` | 1000 | 5 minutes | 60 minutes | If an IP Address rate limit is encountered, it will contain the `finch_code`: [finch\_api\_ip\_rl](/api-reference/development-guides/errors/Error-Types#error-types-1) in the response body. ```json theme={null} // HTTP 429 response body for application rate limit exceeded { "statusCode": 429, "status": 429, "code”: 429, "message": "Too many requests for token", "name": "rate_limit_exceeded_error", "finch_code": "finch_api_ip_rl" } ``` *** ## Handling Rate Limit Errors If you are experiencing rate limits, there are several ways to minimize the risk of hitting rate limits highlighted in our [Handling Rate Limit Errors](/implementation-guide/Backend-Application/Mitigate-Errors#rate-limit-errors) Best Practices guide. # API Versioning Source: https://developer.tryfinch.com/api-reference/development-guides/Versioning We periodically release new, dated versions of the API whenever we make breaking changes. Although we try to only make backward-compatible changes, sometimes we have to make a breaking change to iterate on the API. In addition to the below, please also reference our [API Changes](/developer-resources/api-changes) page for more details and creating a robust integration. **We consider the following changes backward compatible** * Adding new API endpoints * Adding new optional parameters to existing endpoints * Adding new data elements to existing responses * Adding new error types Our current version is **2020-09-17** The `Finch-API-Version` header must be set for every single request to our API. # Error Handling Source: https://developer.tryfinch.com/api-reference/development-guides/errors/Error-Handling ## Errors ### 500 Internal Server Errors Server errors indicate an error on Finch's side and return an HTTP response with a `500` status code. **Common causes** * Finch is experiencing internal system issues. This is rare. * The underlying employment system is experiencing internal system issues. * Finch received an unsupported response from the underlying employment system and is unable to process it. These are usually quickly resolved by our support team. * The end-user has intentionally or unintentionally revoked Finch's access to their system. This is usually returned as a `401 - reauthenticate_user` error but can sometimes be returned as `500 - server_error`. **Troubleshooting steps** * Retrying immediately usually will not resolve the issue. We recommend retrying the API request in a few hours. * If the error persists, submit a support ticket with the `Finch-Request-ID` present in the headers of the response. ### 401 re-authentication errors Authentication errors indicate an error on the end user's side. See the [re-authentication docs](/developer-resources/Reauthentication) for more on common causes and troubleshooting steps. ### 408 client connection errors Timeout errors occur when a client connection is closed while the API server is still processing the request. Currently, our server timeout is set to 6 minutes. Therefore, our recommendation is to increase the configured client timeout to 6 minutes to ensure that the client does not timeout prematurely. If you have not configured one explicitly, there is likely a default depending on the request library you're using. Note, it's not common that our API takes this long to service a request. ## Batch Requests A number of Finch endpoints (like `/individual`, `/employment`, and `/pay-statement`) are batch endpoints. For such endpoints, Finch can return errors in two ways: 1. Return an error per batch request item within the response body. The error will be in the same format described in the [Error Types guide](/api-reference/development-guides/errors/Error-Types). * Finch also returns an `error_name` and `error_message` in the response body. **These fields are deprecated in favor of conforming to our standard error formatting.** 2. Return an error at the HTTP status code level. The error will be in the same format described in the [Error Types guide](/api-reference/development-guides/errors/Error-Types). Ensure your application can handle both types of errors from a batch API call. ```jsx Response level theme={null} Response HTTP Status Code: 200 Response Body: { "responses": [ { // this id varies by endpoint, could also be payment_id or benefit_id "individual_id": "fbeabe51-e6d2-45aa-a460-4c8482528f41", // corresponds to the `code` parameter of the error schema in the Error Types guide "code": 404, "body": { "name": "not_found_error", "code": 404, "finch_code": "individual_not_found", "message": "The individual with id 'fbeabe51-e6d2-45aa-a460-4c8482528f41' could not be found", // deprecated field. corresponds to the `name` parameter of the error schema in the Error Types guide "error_name": "not_found_error", // deprecated field. corresponds to the `message` parameter of the error schema in the Error Types guide "error_message": "The individual with id 'fbeabe51-e6d2-45aa-a460-4c8482528f41' could not be found" } } ] } ``` ```jsx Status code level theme={null} Response HTTP Status Code: 500 Error Body: { "code": 500, "name": "server_error", "message": "Internal server error" } ``` Refer to the API reference to ensure your application handles errors from each batch endpoint correctly as response schemas vary by endpoint. # Error Types Source: https://developer.tryfinch.com/api-reference/development-guides/errors/Error-Types In case of an error, Finch's API will respond with an appropriate HTTP status code and error body. Finch uses HTTP status codes to indicate the success or failure of an API request. * `2xx`: indicates success * `4xx`: indicates developer or user-related errors * `5xx`: indicates Finch-related issues ## Error Schema | Name | Type | Description | | ------------ | --------- | -------------------------------------------------------------------------------------------- | | `code` | `integer` | The HTTP status code of the response. | | `name` | `string` | An identifier, safe for programmatic use, describing the broad error category. | | `finch_code` | `string` | An optional identifier describing the error in more detail. It is safe for programmatic use. | | `message` | `string` | A developer friendly message explaining the error. | ## Error Types | Name | Finch Code | Code | Description | | ----------------------------- | ---------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid_grant_error` | | 400 | The authorization code is invalid. | | `bad_request` | `invalid_request` | 400 | Failed to validate request. | | `bad_request` | `enrollment_not_found` | 404 | Failed find the enrollment for an individual in a benefit. | | `invalid_token_error` | | 401 | The `access_token` is incorrect. | | `invalid_request_error` | | 401 | The request does not match the docs. Example: the request is missing a query parameter. | | `authentication_error` | `reauthenticate_user` | 401 | The user will need to reconnect their employment system. [See more here](/implementation-guide/Backend-Application/Mitigate-Errors#reauthentication-errors). | | `authentication_error` | `account_setup_required` | 401 | The user will need to connect their employment system. | | `invalid_client_error` | | 401 | The provided application credentials were incorrect. Relevant to the `/auth/token` endpoint. | | `unauthorized_request_error` | | 401 | The `access_token` is missing from the header. | | `payment_required` | `payment_required` | 402 | The application has unpaid invoices and cannot access the Finch API until payment is settled. | | `error_permissions` | `insufficient_account_permissions` | 403 | The user will need to update the permissions assigned to the third-party admin account. | | `insufficient_scope_error` | | 403 | The application credentials have insufficient permissions to access the requested product. | | `not_found_error` | `item_not_found` | 404 | The requested resource could not be found. | | `not_found_error` | `benefit_not_found` | 404 | The requested benefit could not be found. | | `not_found_error` | `individual_not_found` | 404 | The requested individual could not be found. | | `not_found_error` | `payment_not_found` | 404 | The requested payment could not be found. | | `client_connection_closed` | | 408 | The client connection is closed while the API server is still processing the request. Currently, our server timeout is set to 6 minutes. | | `unprocessable_request_error` | `unsupported_parameters` | 422 | Parameters provided are not supported by the provider or benefit. Relevant to the `/employer/benefits/*` endpoints. | | `unprocessable_request_error` | `invalid_employee_enrollment` | 422 | The employee is unable to be enrolled in a benefit due specific to constraints on the provider side. Relevant to the `/employer/benefits/*` endpoints. | | `rate_limit_exceeded_error` | `finch_application_rl` | 429 | The application has exceeded Finch's [application rate limits](/api-reference/development-guides/Rate-Limits#application-rate-limits). | | `rate_limit_exceeded_error` | `finch_api_ip_rl` | 429 | The application has exceeded Finch's [IP Address rate limits](/api-reference/development-guides/Rate-Limits#ip-address-rate-limits). | | `rate_limit_exceeded_error` | `finch_auth_ip_rl` | 429 | The application has exceeded Finch Connect rate limits. See [rate limit errors](/implementation-guide/Backend-Application/Mitigate-Errors#rate-limit-errors). | | `rate_limit_exceeded_error` | `upstream_rate_limit_exceeded` | 429 | The application has exceeded the upstream provider's rate limits. See [rate limit errors](/implementation-guide/Backend-Application/Mitigate-Errors#rate-limit-errors). | | `server_error` | | 500 | The server experienced an unexpected error. | | `not_implemented_error` | | 501 | Finch does not support this specific endpoint for this specific provider. | | `bad_gateway_error` | `upstream_provider_error` | 502 | The server experienced an unexpected error while interacting with an upstream service, such as a provider. | # Get Document Source: https://developer.tryfinch.com/api-reference/documents/get-document get /employer/documents/{document_id} **Beta:** This endpoint is in beta and may change. Retrieve details of a specific document by its ID. # List Documents Source: https://developer.tryfinch.com/api-reference/documents/get-documents get /employer/documents **Beta:** This endpoint is in beta and may change. Retrieve a list of company-wide documents. # Create Access Token Source: https://developer.tryfinch.com/api-reference/management/create-access-token post /auth/token Exchange the authorization code for an access token # Disconnect Source: https://developer.tryfinch.com/api-reference/management/disconnect post /disconnect Disconnect one or more `access_token`s from your application. Deletion is based on both the employer and provider of the `access_token` used to call this endpoint, and will also delete all tokens with the same employer/provider pair. Other tokens for the same employer, but connected to a different provider, require a separate call. We require applications to implement the Disconnect endpoint for billing and security purposes. # Disconnect Entity Source: https://developer.tryfinch.com/api-reference/management/disconnect-entity post /disconnect-entity Disconnect entity(s) from a connection without affecting other entities associated with the same connection. Disconnection is scoped to the `entity_id(s)` provided in the request body. The entity(s) must belong to the connection associated with the `access_token` used to call this endpoint. All other entities linked to the same connection remain active and unaffected. If you need to disconnect all entities under a connection at once, use the [Disconnect](/api-reference/management/disconnect) endpoint instead. # Enqueue a New Automated Job Source: https://developer.tryfinch.com/api-reference/management/enqueue-a-new-automated-job post /jobs/automated Enqueue an automated job. `data_sync_all`: Enqueue a job to re-sync all data for a connection. `data_sync_all` has a concurrency limit of 1 job at a time per connection. This means that if this endpoint is called while a job is already in progress for this connection, Finch will return the `job_id` of the job that is currently in progress. Finch allows a fixed window rate limit of 1 forced refresh per hour per connection. `w4_form_employee_sync`: Enqueues a job for sync W-4 data for a particular individual, identified by `individual_id`. This feature is currently in beta. This endpoint is available for *Scale* tier customers as an add-on. To request access to this endpoint, please contact your Finch account manager. # Introspect Source: https://developer.tryfinch.com/api-reference/management/introspect get /introspect Read account information associated with an `access_token` # List All Automated Jobs Source: https://developer.tryfinch.com/api-reference/management/list-all-automated-jobs get /jobs/automated Get all automated jobs. Automated jobs are completed by a machine. By default, jobs are sorted in descending order by submission time. For scheduled jobs such as data syncs, only the next scheduled job is shown. # Providers Source: https://developer.tryfinch.com/api-reference/management/providers get /providers Return details on all available payroll and HR systems. # Request Forwarding Source: https://developer.tryfinch.com/api-reference/management/request-forwarding post /forward The Forward API allows you to make direct requests to an employment system. If Finch's unified API doesn't have a data model that cleanly fits your needs, then Forward allows you to push or pull data models directly against an integration's API. # Retrieve a Manual Job Source: https://developer.tryfinch.com/api-reference/management/retrieve-a-manual-job get /jobs/manual/{job_id} Check the status and outcome of a job by `job_id`. This includes all deductions jobs including those for both automated and assisted integrations. # Retrieve an Automated Job Source: https://developer.tryfinch.com/api-reference/management/retrieve-an-automated-job get /jobs/automated/{job_id} Get an automated job by `job_id`. # Company Source: https://developer.tryfinch.com/api-reference/organization/company get /employer/company Read basic company data # Directory Source: https://developer.tryfinch.com/api-reference/organization/directory get /employer/directory Read company directory and organization structure # Employment Source: https://developer.tryfinch.com/api-reference/organization/employment post /employer/employment Read individual employment and income data Note: Income information is returned as reported by the provider. This may not always be annualized income, but may be in units of bi-weekly, semi-monthly, daily, etc, depending on what information the provider returns. # Individual Source: https://developer.tryfinch.com/api-reference/organization/individual post /employer/individual Read individual data, excluding income and employment data # Create Rule Source: https://developer.tryfinch.com/api-reference/payroll/create-rule post /employer/pay-statement-item/rule Custom rules can be created to associate specific attributes to pay statement items depending on the use case. For example, pay statement items that meet certain conditions can be labeled as a pre-tax 401k. This metadata can be retrieved where pay statement item information is available. # Delete Rule Source: https://developer.tryfinch.com/api-reference/payroll/delete-rule delete /employer/pay-statement-item/rule/{rule_id} Delete a rule for a pay statement item. # Ledger Items Source: https://developer.tryfinch.com/api-reference/payroll/get-ledger-items post /employer/ledger-items Read the ledger entries for one or more payments. **Beta** — This endpoint is currently available for **Gusto** only. Endpoint paths and field names may change before general availability. # Get Pay Group Source: https://developer.tryfinch.com/api-reference/payroll/get-pay-group get /employer/pay-groups/{pay_group_id} Read information from a single pay group # Get All Pay Groups Source: https://developer.tryfinch.com/api-reference/payroll/get-pay-groups get /employer/pay-groups Read company pay groups and frequencies # Pay Statement Item Source: https://developer.tryfinch.com/api-reference/payroll/get-pay-statement-items get /employer/pay-statement-item Retrieve a list of detailed pay statement items for the access token's connection account. # Get Rules Source: https://developer.tryfinch.com/api-reference/payroll/get-rules get /employer/pay-statement-item/rule List all rules of a connection account. # Pay Statement Source: https://developer.tryfinch.com/api-reference/payroll/pay-statement post /employer/pay-statement Read detailed pay statements for each individual. Deduction and contribution types are supported by the payroll systems that supports Benefits. # Payment Source: https://developer.tryfinch.com/api-reference/payroll/payment get /employer/payment Read payroll and contractor related payments by the company. # Update Rule Source: https://developer.tryfinch.com/api-reference/payroll/update-rule put /employer/pay-statement-item/rule/{rule_id} Update a rule for a pay statement item. # Create a new sandbox account Source: https://developer.tryfinch.com/api-reference/sandbox/create-sandbox-account post /sandbox/connections/accounts Create a new account for an existing connection (company/provider pair) # Create a new Sandbox Connection Source: https://developer.tryfinch.com/api-reference/sandbox/create-sandbox-connection post /sandbox/connections Create a new connection (new company/provider pair) with a new account # Add new individuals to a sandbox company Source: https://developer.tryfinch.com/api-reference/sandbox/create-sandbox-employee post /sandbox/directory Note that requests using the SDK will require a JSON object with a key of `body` and a value of an array of individuals. ``` // JavaScript example await client.sandbox.directory.create({ body: [ // list of individual objects ] }) ``` # Add a new sandbox payment Source: https://developer.tryfinch.com/api-reference/sandbox/create-sandbox-payment post /sandbox/payment All fields are optional. If you don't provide a start and end date, the default `start_date` is one business day after the `end_date` of the most recently created payment, and the default `end_date` is `start_date` + 14 business days. The default `pay_date` is the `end_date` and the default `debit_date` is one business day after the `pay_date`. You may override any fields in the pay statements you would like. By default, no taxes, earnings or deductions are created (unless an individual is enrolled in deductions via the `/benefits` endpoints). # Get configurations for sandbox jobs Source: https://developer.tryfinch.com/api-reference/sandbox/get-sandbox-jobs-configuration get /sandbox/jobs/configuration # Enqueue a new sandbox job Source: https://developer.tryfinch.com/api-reference/sandbox/refresh-job post /sandbox/jobs Analogous to [`POST /jobs/automated`](/api-reference/management/enqueue-a-new-automated-job), but for automated and assisted Finch Sandbox connections. Use this endpoint after updating a Finch Sandbox connection's data to "sync" the data with Finch and see it reflected in `/employer` data API calls. Assisted connections will return `null` for `job_id` and `job_url`, since no job is actually being created. Simply call this endpoint, and then call the `/employer` API to see the updated data. # Update a sandbox account Source: https://developer.tryfinch.com/api-reference/sandbox/update-sandbox-account put /sandbox/connections/accounts Update an existing sandbox account. Change the connection status to understand how the Finch API responds. # Update a sandbox company's data Source: https://developer.tryfinch.com/api-reference/sandbox/update-sandbox-company put /sandbox/company # Update sandbox employment Source: https://developer.tryfinch.com/api-reference/sandbox/update-sandbox-employment put /sandbox/employment/{individual_id} # Update sandbox individual Source: https://developer.tryfinch.com/api-reference/sandbox/update-sandbox-individual put /sandbox/individual/{individual_id} # Update configurations for sandbox jobs Source: https://developer.tryfinch.com/api-reference/sandbox/update-sandbox-jobs-configuration put /sandbox/jobs/configuration # Build or audit a Finch integration with AI agents Source: https://developer.tryfinch.com/developer-resources/Build-or-Audit-with-AI Finch Integration Skills guide an AI agent through building a new Finch integration or auditing an existing one — answer questions about your stack and get reviewable code, or point the agent at your repo and get a findings report. The Finch Integration Skills are a set of AI agent skills that guide an AI coding agent through building or auditing a Finch integration. Two skills — one backend, one frontend — build a new integration. You answer about ten questions about your stack and use case, and the agent generates the integration code and tests for each component: Finch Connect, token management, API calls, webhooks, and reauthentication. A third skill audits an integration you already have. Point it at your repo instead of answering setup questions, and it checks your existing backend and/or frontend code against the same rules the build skills use to generate code, then produces a severity-rated findings report — no code changes unless you ask for them afterward. See [Audit an existing integration](#audit-an-existing-integration). The skills handle the integration plumbing. The application logic on top of the data — how you process, display, and act on it — remains yours to build. **Beta.** The Finch Integration Skills are in active development. The Finch team continues to test and improve them. As with all AI-generated code, treat the output as a starting point, not production-ready code. Review it against the [Finch docs](/how-finch-works/finch-overview) and [API reference](/api-reference), test it thoroughly, and revise it before you deploy. ## What the skills generate There are three skills: backend, frontend, and audit. Load the backend and frontend skills together for a fullstack build, or load only the one for the layer you own — the backend skill ends at "return the session token to the frontend"; the frontend skill starts there. Load the audit skill instead of either when you already have an integration and want it reviewed, not rebuilt. **Backend skill** generates: * Finch Connect session creation for the embedded and redirect flows, with reauthentication routing when a connection breaks * Authorization code exchange, access token encryption, and database persistence * A reusable Finch API client with rate limiting, pagination, and error handling * A data fetcher for each product scope you select, with upsert logic * A webhook handler with signature verification and event routing * A database schema and tests — unit tests with mocked HTTP, plus integration tests against the Finch Sandbox **Frontend skill** generates: * A Connect button that fetches a session and launches Finch Connect * Embedded launch through the Finch React or JavaScript SDK, or the redirect flow with no SDK * Authorization code handoff to your backend on success * A reauthentication UI — a banner or settings-page component that re-launches Finch Connect when a connection breaks * Tests — component tests and end-to-end tests against the Finch Sandbox **Audit skill** produces, instead of code: * An inventory of what's actually implemented — Connect flow type, product scopes, entity handling, reauthentication, disconnect, webhooks, token storage, test coverage — for the backend, frontend, or both in one pass * A check of that inventory against the backend and frontend skills' own correctness rules, plus a set of known deprecated patterns * A severity-rated findings report, with file:line evidence and a fix recommendation for each finding, cross-referenced to the relevant backend or frontend skill step * Fixes, only for findings you explicitly ask it to address afterward, implemented one at a time following the corresponding backend/frontend skill guidance The backend and frontend skills are language- and framework-agnostic. Generated code is tailored to the stack you name. The backend skill generates native HTTP implementations and does not use a Finch backend SDK. This keeps the generated code self-contained and consistent across languages. The frontend skill does use the Finch Connect SDK for the embedded flow. ## Prerequisites You need an AI tool that can load a `SKILL.md` file — for example, Claude Code, Cursor, or Codex CLI. The skill drives the workflow; your agent generates the code. **Required.** The skill provides the workflow structure; the Finch documentation MCP server supplies the specifics — current endpoint details, field names, response shapes, error codes, and SDK versions — while your agent generates code. The two are designed to work together, and the skill assumes the MCP server is connected. The server URL is `https://developer.tryfinch.com/mcp`. It's public — no credentials or Finch account required to connect. Add the server from the terminal: ```bash theme={null} claude mcp add --transport http finch-docs https://developer.tryfinch.com/mcp ``` Confirm it connected: ```bash theme={null} claude mcp list ``` `finch-docs` should show as connected. This adds the server at the user level, so it's available in any project — add `--scope project` instead if you only want it in the current one. 1. Go to [claude.ai/settings/connectors](https://claude.ai/settings/connectors). 2. Click **Add custom connector**. 3. Enter a name (for example, `Finch docs`) and the URL `https://developer.tryfinch.com/mcp`. 4. Click **Add**. 5. In a chat, click the attachments (plus) icon and select the connector to make it available. Most MCP-capable tools support adding a remote server by URL — for example, Cursor and VS Code take a `url` entry in an `mcp.json` file. Check your tool's documentation for the exact syntax; the value you need in every case is the same URL above. You need a Sandbox application and its `client_id` and `client_secret`. The generated integration tests run against the Finch Sandbox. Sandbox and Production are separate applications with separate credentials — register redirect URIs and webhook endpoints in each. Create an account at [dashboard.tryfinch.com](https://dashboard.tryfinch.com). **If the MCP server isn't connected, the skill still runs — but expect gaps.** The skill falls back to web search or its own training data to fill in specifics it would otherwise look up live. This can produce code that references outdated field names or response shapes, an outdated SDK version or API surface, or an incomplete set of product scopes or webhook events — errors that surface as failed tests or runtime errors against the Sandbox, not as warnings during code generation. Connect the MCP server before starting the skill, not after something breaks. **This is not the same MCP as the [Finch MCP Server](/developer-resources/Finch-MCP-Server).** Finch has two separate MCP servers with similar names: | | Finch documentation MCP | [Finch MCP Server](/developer-resources/Finch-MCP-Server) | | ------------ | -------------------------------------- | ----------------------------------------------------------------- | | **Purpose** | Searches Finch's documentation | Calls the live Finch API | | **Acts on** | Published docs and API reference | A specific employer connection's real data | | **Requires** | Nothing — no credentials | A Finch `access_token` for that connection | | **Used for** | Building this integration (this guide) | Querying employee/payroll data in natural language once connected | The Finch Integration Skills use the **documentation MCP server** described above. Connecting the Finch MCP Server instead won't give the skill what it needs — it has no way to look up documentation. ## Load the skills Because the [Finch documentation MCP server](#prerequisites) is already required, the simplest way to load a skill is straight from that connection — the server exposes all three skills as MCP resources, so your agent can pull the one it needs with no separate install: * **Claude Code:** in the prompt, type `@` to open the resource picker and select the skill you need — backend, frontend, or audit — from the `finch-docs` server (whatever name you gave it in [Step 2](#prerequisites)). Load backend and frontend together for a fullstack build; load audit on its own to review an existing integration. * **Other MCP clients:** look for the resource or attachment picker tied to the connected server. The UI varies by tool, but the mechanism — an MCP resource, not a downloaded file — is the same. If your agent isn't connected to the MCP server or doesn't support MCP resources, point it at the raw `SKILL.md` files directly: * Backend — `https://developer.tryfinch.com/.well-known/agent-skills/finch-integration-backend/SKILL.md` * Frontend — `https://developer.tryfinch.com/.well-known/agent-skills/finch-integration-frontend/SKILL.md` * Audit — `https://developer.tryfinch.com/.well-known/agent-skills/finch-integration-audit/SKILL.md` You don't need `npx skills add` for these skills. The documentation MCP server is already required and serves the skills as MCP resources, so connecting it is enough. The [skills CLI](https://www.npmjs.com/package/skills) (`npx skills add https://developer.tryfinch.com`) is an optional alternative if you'd rather install the skills into your agent's context instead of pulling them from the MCP connection. ## How it works This section describes the backend and frontend skills' build flow. For the audit skill, which doesn't ask setup questions, see [Audit an existing integration](#audit-an-existing-integration) below. Tell your agent you want to build a Finch integration and point it at the skill. The backend and frontend skills each open with a short setup questionnaire. Each skill runs through a short setup questionnaire before generating anything. Expect to cover: * Your stack — language, framework, database, and test framework * Your integration setup — new app or existing one, product scopes, and Connect flow * Your operational choices — how you identify each employer, reauthentication and webhook strategy, token storage, and test coverage Answer each section before the agent continues. Your answers shape the generated code. The agent generates each component as a labeled, copy-ready section, with comments that link back to the relevant Finch documentation. Read it against the docs, adjust with follow-up prompts, and run the tests. Run the generated integration tests against your Sandbox application. Complete a full Connect flow in the Sandbox before you point the integration at Production. ## Audit an existing integration Use the audit skill instead of the backend or frontend skill when you already have a Finch integration and want it checked for gaps — not built from scratch. Reach for it when the question is "is our existing integration missing anything?" rather than "help me build this." The audit skill covers both layers in a single pass — point it at your backend, your frontend, or both, and it reports findings for whichever you include. You don't need to run the backend and frontend skills separately to get equivalent coverage; the audit skill loads their checklists itself and evaluates your code against both. The audit skill still depends on the backend and frontend skills — it fetches their audit criteria directly from the skill files, rather than duplicating them, via the Finch documentation MCP server or directly from the [backend](https://developer.tryfinch.com/.well-known/agent-skills/finch-integration-backend/SKILL.md) and [frontend](https://developer.tryfinch.com/.well-known/agent-skills/finch-integration-frontend/SKILL.md) skill URLs. If that fetch fails, expect your agent to say so before proceeding — a report built only from general knowledge of Finch Connect is lower-confidence and shouldn't be presented as a full audit against the current checklist. To prompt it, tell your agent what to audit and point it at the skill — for example: > Audit my existing Finch integration for gaps using the Finch integration audit skill. It's in `src/integrations/finch` on the backend and `src/components/connect` on the frontend — check both. Or, if you already suspect a specific issue: > Run the Finch integration audit skill on our backend only. Reauthentication doesn't seem to be triggering when a connection breaks — investigate that end-to-end, and check everything else too. Even when you lead with a bug you're confident is real and expect a quick patch, expect the same discovery pass and a written report first, not an immediate fix — the audit skill investigates and confirms every finding, including one you already suspected, before changing any code. The skill produces a written report only — findings with file:line evidence, severity, and remediation guidance. Review the report, then ask it to implement specific fixes one at a time as a separate, explicit follow-up if you want it to; it follows the corresponding backend or frontend skill's guidance for each fix rather than improvising one. ## What's yours to build * **Application logic is yours.** The skills handle the integration plumbing — authentication, token management, API calls, webhooks — the high-effort work that looks similar across most Finch integrations. How your application processes, displays, and acts on the data takes additional development tailored to your use case. * **Verify against the docs.** Use the [Implementation Guide](/implementation-guide/go-live-checklist) and [API reference](/api-reference) to confirm the generated code matches current Finch API behavior. Response shapes change across API versions. * **The skills work best together.** A fullstack developer should load both — the backend skill ends at the session token, the frontend skill starts there. Expect to iterate with additional prompts to fit the generated code to your application. ## Time to integrate You can answer the setup questions in under an hour and receive every component, then shift your time from writing integration code to reviewing, testing, and adapting it. Actual savings vary with your application's complexity and how many revision cycles it takes, but most teams save several days to a few weeks compared to writing the plumbing by hand. For the audit skill, a pass is typically one agent conversation instead of a multi-day manual review. ## Next steps How Finch Connect sessions and the embedded and redirect flows work. Endpoint details, field definitions, and response shapes to verify generated code. What happens when a connection breaks and how to recover it. Test your integration end-to-end before going to Production. # W-2 Box 1 Source: https://developer.tryfinch.com/developer-resources/Calculating-W2-Box1-value Finch's data can be used to run an individual's W-2 Box 1 calculation using data returned from Finch Pay endpoints. **Box 1 is defined in the IRS' ["2024 General Instructions for Forms W-2 and W-3" published guidance](https://www.irs.gov/pub/irs-pdf/iw2w3.pdf) as:** > Wages, tips, other compensation. Show the total taxable wages, tips, and other compensation that you paid to your employee during the year. However, do not include elective deferrals (such as employee contributions to a section 401(k) or 403(b) plan) except section 501(c) (18) contributions. > Include the following. 1. Total wages, bonuses (including signing bonuses), prizes, and awards paid to employees during the year. See Calendar year basis. 2. Total noncash payments, including (...) 24. Salary reduction contributions made to a Roth IRA pursuant to a SEP arrangement or SIMPLE IRA plan. See SEP arrangements and SIMPLE IRA plans. ### Tabulated IRS criteria: | # | IRS Text | Occurence | Group | | -- | :-------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | :---------------------------------------------------------------------------- | | 1 | "Total wages, bonuses (including signing bonuses), prizes, and (...) full text | ALWAYS | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 2 | "Total noncash payments, including certain fringe benefits. See Fringe benefits." | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 3 | "Total tips reported by the employee to the employer (not allocated tips)." | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 4 | "Certain employee business expense reimbursements. See Employee business expense reimbursements." | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 5 | "The cost of accident and health insurance premiums for 2%-or-more shareholder-employees paid by an S corporation." | RARE | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 6 | "Taxable benefits from a section 125 (cafeteria) plan if the employee chooses cash." | RARE | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 7 | "Employee contributions to an Archer MSA." | N/A | [Deduction](/how-finch-works/unified-employment-api-glossary#deduction) | | 8 | "Employer contributions to an Archer MSA if includible in the income of the employee. See Archer MSA." | N/A | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 9 | "Employer contributions for qualified long-term care services to the extent (...) full text | RARE | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 10 | "Taxable cost of group-term life insurance in excess of \$50,000. See Group-term life insurance." | COMMON | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 11 | "Unless excludable under Educational assistance programs, payments for (...) full text | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 12 | “The amount includible as wages because you paid your employee’s share of social security and (...) full text | ALWAYS | [Tax](/how-finch-works/unified-employment-api-glossary#tax) | | 13 | "Designated Roth contributions made under a section 401(k) plan, a section 403(b) salary (...) full text | COMMON | [Deduction](/how-finch-works/unified-employment-api-glossary#deduction) | | 14 | "Distributions to an employee or former employee from an NQDC plan (including a rabbi trust) or a nongovernmental section 457(b) plan." | RARE | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 15 | "Amounts includible in income under section 457(f) because the amounts are no longer subject to a substantial risk of forfeiture." | RARE | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 16 | "Payments to statutory employees who are subject to social security and Medicare taxes but (...) full text | RARE | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 17 | "Cost of current insurance protection under a compensatory split-dollar life insurance arrangement." | RARE | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 18 | "Employee contributions to a health savings account (HSA)." | COMMON | [Deduction](/how-finch-works/unified-employment-api-glossary#deduction) | | 19 | "Employer contributions to an HSA if includible in the income of the employee. See Health savings account (HSA)." | COMMON | [Contribution](/how-finch-works/unified-employment-api-glossary#contribution) | | 20 | "Amounts includible in income under section 409A from an NQDC because the amounts are (...) full text | RARE | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 21 | "Nonqualified moving expenses and expense reimbursements. See Moving expenses." | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 22 | "Payments made to former employees while they are on active duty in the U.S. Armed Forces or other uniformed services." | RARE | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 23 | "All other compensation, including certain scholarship and fellowship grants (...) full text | COMMON | [Earning](/how-finch-works/unified-employment-api-glossary#earning) | | 24 | "Salary reduction contributions made to a Roth IRA pursuant to a SEP arrangement or (...) full text | RARE | [Deduction](/how-finch-works/unified-employment-api-glossary#deduction) | ### Finch implementation: **All of the information necessary to run an individual’s W-2 Box 1 calculation can be found in [Finch’s Pay Statement data](/api-reference/payroll/pay-statement).** The table above highlights where to find criteria within [Pay Statement object groups (Earning, Tax, Deduction, Contribution)](/api-reference/payroll/pay-statement). The majority of these criteria require simple summing of line-item-amounts over a given calendar year - [Finch’s type classification](/developer-resources/Pay-Statement-Type-Classification#pay-statement-type-classification) is invaluable for properly aggregating criteria values. ### Nuanced criteria guidance: 10. Calculate per pay-period OR on 12/31 check - determine the cost of group-term life insurance provided over the \$50,000 income exclusion threshold. Want to talk through how to do this with a Finch teammate? Reach out to your DSE or AM. ***this general guidance must be used at the discretion of Finch's developers*** # Calculate Year-To-Date (YTD) Wages Source: https://developer.tryfinch.com/developer-resources/Calculating-YTD-Wages Learn how to calculate year-to-date (YTD) gross wages for individual employees using data returned from Finch Organization endpoints. A common use case for Finch APIs is to calculate YTD gross wages for individual employees. This useful and powerful information can be calculated easily by using the right approach. ### Logic Flow The general flow for calculating individual YTD wages works like this: 1. Call the `/payment` endpoint and pass a `start_date` of the first day of the year (January 01) and an `end_date` of the current date. 2. Loop over the array of returned payment objects and collect all of the payment `id`s. 3. Call the `/pay-statement` endpoint and pass all of the `payment_id`s as a batched request. 4. Loop over the array of returned pay statements and aggregate each individual's gross pay amounts. ### Sequence Diagram ytd-gross-wages.png # Data Access Controls Source: https://developer.tryfinch.com/developer-resources/Data-Access-Controls Learn how to disable fields from API responses. ## Overview Data Access Controls allow developers to selectively disable specific fields from API responses. This ensures that only the necessary data is retrieved, improving transparency and reducing over-permissioning concerns for employers during the Finch Connect flow. When a field is disabled: * It will **not** appear in the API response, returning `null` instead. * It will **not** be displayed on the permissions screen in Finch Connect. This feature is only available to customers on a Pro or Premier plan, and will not affect data returned by flat file. ## How It Works Each endpoint's fields are grouped into logical categories. If a developer includes **any** fields within a group, the recommended Finch Connect verbiage for that group will be displayed. If **all** fields in a group are excluded, the verbiage will be omitted from Finch Connect to provide a streamlined experience. ### Company Data If a developer is requesting **all** fields, the Connect verbiage will display: > "Read basic company data, company contact info, address details, and bank account data." | Group | Fields | Connect Verbiage | | ------------------- | ------------------------------------------------------- | ------------------------- | | Basic Company Data | Legal name, Entity type, Subtype, Departments, EIN | Read basic company data | | Contact Info | Primary Email, Primary Phone Number | Read company contact info | | Address Details | Location Line 1, Location Line 2, City, State, Zip Code | Read address details | | Banking Information | Bank Account Routing, Bank Account Number | Read bank account data | ### Directory Data If a developer is requesting **all** fields, the Connect verbiage will display: > ""Read company directory and organization structure." | Group | Fields | Connect Verbiage | | ---------------------- | ------------------------ | --------------------------- | | Company Directory | Employee Name, Is Active | Read company directory | | Organization Structure | Manager, Department | Read organization structure | ### Individual Data If a developer is requesting **all** fields, the Connect verbiage will display: > "Read individual data, contact info, and address details." | Group | Fields | Connect Verbiage | | ---------------------------- | ----------------------------------------------------- | -------------------- | | Employee Identification | Employee Name, Preferred Name, DOB, Gender, Ethnicity | Read individual data | | Employee Contact Information | Email, Phone Number | Read contact info | | Employee Address Details | Address Line 1, Address Line 2, City, State, Zip Code | Read address details | ### Employment Data If a developer is requesting **all** fields, the Connect verbiage will display: > "Read individual employment and income data." | Group | Fields | Connect Verbiage | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | | Employment Details | Title, Manager, Department, Employment Type, Subtype, Start Date, End Date, Latest Rehire Date, Is Active, Employment Status, Work Location Line 1, Work Location Line 2 | Read individual employment data, excluding income | | Compensation | Income | Read income data | | Additional Information | Class Code, Custom Fields | - | ## Getting Started To configure Data Access Controls for your application: 1. Review the available field groupings above and determine which fields you need. 2. Contact [developers@tryfinch.com](mailto:developers@tryfinch.com) with your selected field restrictions. 3. Once enabled, your API responses will return `null` for any disabled fields, and Finch Connect will dynamically adjust permission verbiage accordingly. 4. For any questions or additional support, reach out to your Developer Success Engineer. # Data Syncs Source: https://developer.tryfinch.com/developer-resources/Data-Syncs Learn how Finch syncs data after an employer connects and how you can verify the freshness and scope of the data you receive. ## Initial Data Syncs After an employer connects through Finch Connect, Finch automatically initiates an initial sync to retrieve available data across supported endpoints. Effective June 11, 2025 Finch will fetch the following for Pay data: * 2 full years of historical data * Year-to-date for the current calendar year **Example:** If an employer connects on June 1, 2025, Finch will sync data starting from January 1, 2023. If an employer connects on January 2, 2026, Finch will sync data starting from January 1, 2024. Finch defaults to a 2-year plus year-to-date lookback to ensure fast, reliable first-time syncs. Longer lookbacks are available on our Premier plan but may increase the risk of time-outs. To request a custom lookback, contact [developers@tryfinch.com](mailto:developers@tryfinch.com). Finch will fetch Organization data going as far back as is available in the payroll system. ### Provider limitations Some providers restrict how much historical data is available. * Paychex Flex: up to 14 months of pay statement data * Paycom: up to 2 years of pay statement data If a request is made before the initial sync is complete, Finch will attempt a live fetch from the provider. These requests may take longer, depending on the size and structure of the data. ## Ongoing data syncs After the initial sync, Finch keeps data fresh by syncing on the following schedule: * [Automated](/integrations/integration-types#automated-integrations) providers: every 24 hours * [Assisted](/integrations/integration-types#assisted-integrations) providers: every 7 days Finch API responses always return the most recent successful sync. Most requests complete in under 200 milliseconds. ## Verify data freshness Finch includes response headers that indicate the freshness of the data: | Response Header | Description | | ---------------------------------- | --------------------------------------------------------------------------- | | `Finch-Data-Retrieved` | The date/time that the data was retrieved from the employment system. | | `Finch-Last-Attempted-Update-Date` | The date/time that Finch last attempted to sync the data for this endpoint. | **Multi-Entity data freshness**: For connections that include multiple entities, Finch runs a separate data sync for each entity. To confirm that all entities have fresh data, check the same response headers (`Finch-Data-Retrieved` and `Finch-Last-Attempted-Update-Date`) on a per-entity basis. ## Batch sync behavior For batch endpoints like `/employment`,` /individual`, and `/pay-statement`, Finch syncs all records in a single operation. This ensures that all data returned in the response reflects the same point in time. ## Pay statement sync behavior Pay statements are larger and may take longer to sync than other data types. If you query a pay statement using a payment\_id from the /payment endpoint before it has been fetched, Finch will return a 202 Accepted status with the following response: ```json theme={null} { "responses": [ { "payment_id": "9c8626e3-6d97-48a0-883c-f4c65e736321", "code": 202, "body": { "code": 202, "name": "accepted", "finch_code": "data_sync_in_progress", "message": "The pay statements for this payment are being fetched. Please check back later." } }, ... ] } ``` # Finch Developer FAQs Source: https://developer.tryfinch.com/developer-resources/Developer-FAQs Explore Finch developers' most frequently asked questions (FAQ) and answers. Topics include Products & Integrations, API & Data Model, Security, and more. ## Can you describe Automated vs Assisted connections? Finch is a unified API for employment systems, meaning that the developer is only ever interacting with our single API to GET or POST data to any provider. Depending on which provider is set up, Finch will do one of two things: 1. If the provider supplies an *automated* API, Finch will instantaneously access the data and return it. 2. If the provider has not built an API to access their data easily, a real Finch employee will *assist* in getting this data manually by contacting and retrieving the requested data on a scheduled basis (usually one week) and uploading it so it can be returned instantaneously on every subsequent call. The process of getting this set up for the first time is a few weeks. After the initial setup, new employee data will be refreshed every week without the need to be involved. Our Assisted Connections are particularly powerful since they allow the developer to only interact with Finch APIs without having to deal with SFTP servers, report uploads, or other synchronous data updates for each provider supported. Therefore, your team does not need to build a product operations team that has to filter, map, or ingest data in system-specific formats; Finch does this for you. No other platform offers this level of service and allows for a high level of coverage that would take years to build in-house. *** ## Why are some Finch API endpoints GET requests while others are POST requests? In the Finch API, some endpoints are GET requests (/company and /directory endpoints) while some are POST requests (/individual and /employment endpoints). The latter are POSTs because a request body containing ids needs to be sent. Additionally, the `/individual`, `/employment`, and `/pay-statement` endpoints are special because they are “batch” endpoints, meaning you can send as many ids as you want in the body, and get a single response back containing the information for as many individuals/pay-statements as you sent. Query parameters can’t handle 1000 ids in the URL, hence the need for POSTs using request bodies. *** ## Does Finch display payments to business/vendor subcontractors? No, Finch only includes payments to persons who show up in the employee directory with an associated individual\_id. This applies across all providers. *** ## How can I determine the “Payroll Close Date”? It is usually 1-2 days after payroll end date between `end_date` and `debit_date`. *** ## How is the data returned by Finch validated for accuracy? Finch looks at two broad categories when defining data quality: 1. rate of `NULL` fields when values exist in the system and 2. rate of incorrect fields. Measuring the rate at which we return value = `NULL` can be potentially indicative of 4 things: * The data is unavailable in the system — not a Finch error * The data is available in the system, but the format does not cleanly fit our endpoint — error * We parsed the wrong field and the data we parsed does not fit the expected format — error * We parsed information, but we did not know how to classify it — error The goal is to decrease the rate of `NULL` over time; if the data is available in the provider's system, Finch should be returning that data. Keep in mind that the status of an employee (full-time vs contractor) can also affect which fields return NULL. Finch defines the “rate of incorrect data” as data that does not match what is reported in the provider's system. This could either mean the field returns blank indicating a potential bug in our code (e.g.: a pay statement array returns empty), or the field returns a value that does not reflect what is reported in the system. We have an internal dashboard where we track data field coverage and correctness in real-time. We have alerts defined to notify us of any anomalies detected which we proactively investigate and fix. There are several ways developers can validate data coming from Finch: 1. Implementing “quality checks” on all pay statements to make sure financial data is not missing, duplicated, or inaccurate. 2. Running a series of “blind” audits on a semi-regular schedule. The audits should focus on the two categories mentioned above: rate of nulls and the rate of incorrect data. Employee employment status, currency amounts, and field type categorizations are important data points to watch. There are two ways to conduct an audit of Finch data: 1. The data returned from Finch is compared with previous Finch-connected employer data that have similar providers, use cases, and sizes. Any discrepancies are alerted to Finch. This method is beneficial if you have thorough historical data to pull from. 2. If you do not have enough historical data to use, the data returned from Finch can be compared directly with the data in the provider's system. This method requires contacting the employer and asking either pointed questions about possible data discrepancies or exchanging data extensively. Similarly, if a customer notices a potential data discrepancy, building and including a way for customers to report errors to you is also beneficial. Any errors reported to you can be directly forwarded to Finch for internal investigation. While we don’t ever want inaccurate data returned by our API, we are committed to fixing any errors rapidly and continue to proactively invest in automated tests, checks, and audits internally to catch any data quality errors proactively. If there are any audits or data fields that are important to your business, we want to hear from you so that we can better support you. *** ## Can I bypass the provider selection screen in Finch Connect? You can [bypass the provider screen](/implementation-guide/Deploy-and-Manage/Increase-Employer-Adoption) if you already know the provider name by passing `payroll_provider=` into the `/authorize` url when opening Finch Connect. *** ## How long is the access token lifetime? A Finch `access_token` lifetime is infinite; it does not expire⁠, unless you [disconnect](/implementation-guide/Backend-Application/Disconnect-Connections) it. If a `401 Re-authentication` error is received (either by a user changing their security setting or an employment system makes an infrastructure change), Finch's connection can get disconnected, which requires a user to [reauthenticate](/implementation-guide/Backend-Application/Mitigate-Errors) and a new Finch access\_token will be created and sent back to your app. *** ## How does Finch encrypt data? What type of encryption is used? Finch utilizes various encryption protocols to protect data at rest and in transit. * **Encryption at rest** — All data in our datastores are encrypted using AES-256 with keys managed via AWS KMS. * **Encryption in transit** — All data to or from the Finch infrastructure is encrypted in transit using TLS 1.2. * **Application-level encryption** — Other Highly Restricted fields are additionally encrypted at the application level using AES-256. # Enable Social Security Number (SSN) Field Source: https://developer.tryfinch.com/developer-resources/Enable-SSN-Field In this guide, you'll learn how to enable the social security number (SSN) field in Finch. The SSN field must be explicitly authorized by the employer. SSN is a secure field in the Finch API. Your use case needs to be approved by your Developer Success Representative before enabling. However, you can test SSN via the [Finch Sandbox](/implementation-guide/Test/Finch-Sandbox) without any approval. Finch returns Social Security Number (SSN) as a field in the [/individual](/api-reference/organization/individual) endpoint. However, the SSN field is not returned by default; you must enable it first. To enable SSN, the `ssn` product scope (along with `individual`) must be included in the `/authorize` URL when launching Finch Connect. This ensures that the connection's access tokens that are generated are capable of accessing this field. ## Authorization Make sure to include the `ssn` scope in your authorization URL. ```bash theme={null} https://connect.tryfinch.com/authorize? &client_id= &products=company%20directory%20individual%20employment%20payment%20pay_statement%20ssn &redirect_uri=https://example.com &sandbox=true ``` ## Request ```bash theme={null} curl https://api.tryfinch.com/employer/individual \ -H "Authorization: Bearer {token}" \ -H "Finch-API-Version: 2020-09-17" \ -X "POST" \ -H "Content-Type: application/json" \ -d '{ "options": { "include": ["ssn"] }, "requests": [{ "individual_id": "f3ddb1f4-dfa4-4e1d-bfed-bdfd0645b613"}] }' ``` ## Response SSN values returned from the Finch API can either be in raw or encrypted format, depending on the provider. Please refer to each provider's field support documentation for details on whether SSN is supported in raw or encrypted format, including how to decrypt encrypted values. If you require further assistance, reach out to your Finch Developer Success representative. ### Response with Raw SSN ```json theme={null} { "responses": [ { "individual_id": "f3ddb1f4-dfa4-4e1d-bfed-bdfd0645b613", "code": 200, "body": { "id": "f3ddb1f4-dfa4-4e1d-bfed-bdfd0645b613", "ssn": "143782004", // Don't worry, this value is not a real SSN "encrypted_ssn": null, "first_name": "Angelica", "middle_name": "Aretha", "last_name": "Flatley", "preferred_name": null, "dob": "1968-05-15", "emails": [ { "data": "Angelica.Flatley18@impressive-coinsurance-inc.com", "type": "work" } ], "phone_numbers": [ { "data": "098-478-0472", "type": "work" } ], "gender": "female", "ethnicity": "hispanic_or_latino", "residence": { "line1": "341 Kuphal Lodge", "line2": "Suite 896", "city": "Swiftshire", "state": "AL", "postal_code": "83712-2670", "country": "US" } } } ] } ``` ### Response with Encrypted SSN ```bash theme={null} { "responses": [ { "individual_id": "f3ddb1f4-dfa4-4e1d-bfed-bdfd0645b613", "code": 200, "body": { "id": "f3ddb1f4-dfa4-4e1d-bfed-bdfd0645b613", "ssn": null, "encrypted_ssn": "vlIRzYJ5jk3TDanW3T0Fg2cVyHXPvBbtm.zymmLpbVlrnDUsaW0kbmNnkneTyYJRsJKozu", // This value will need to be decrypted to attain the raw SSN value "first_name": "Angelica", "middle_name": "Aretha", "last_name": "Flatley", "preferred_name": null, "dob": "1968-05-15", "emails": [ { "data": "Angelica.Flatley18@impressive-coinsurance-inc.com", "type": "work" } ], "phone_numbers": [ { "data": "098-478-0472", "type": "work" } ], "gender": "female", "ethnicity": "hispanic_or_latino", "residence": { "line1": "341 Kuphal Lodge", "line2": "Suite 896", "city": "Swiftshire", "state": "AL", "postal_code": "83712-2670", "country": "US" } } } ] } ``` # MCP Source: https://developer.tryfinch.com/developer-resources/Finch-MCP-Server Use the Finch MCP Server to enable natural language access to the Finch API via large language models (LLMs). The Finch MCP Server is currently in **beta**. Features and behavior may change. ## Overview The Finch MCP Server makes it simple to integrate Large Language Models (LLMs) with the Finch API using natural language. Rather than writing custom API calls, you can describe your intent, and the LLM will handle the rest by issuing calls to the Finch API to get the information you need or take action on your behalf. The Finch MCP Server exposes structured tools to LLMs, making it possible to use Finch's API without understanding its full surface area. This unlocks powerful, intuitive workflows for developers, finance teams, support agents, and more. > **MCP** stands for **Model Context Protocol**, a mechanism that defines how LLMs can safely interact with external APIs and tools. ### 💾 Installation Install the MCP Server via npm: ```bash theme={null} npm install @tryfinch/finch-api-mcp ``` ### ⚙️ LLM Configuration To connect the Finch MCP Server to an MCP Client, you will need to add the appropriate configuration to your client. Below is an example of what that may look like. ```json theme={null} { "mcpServers": { "finch_api": { "command": "npx", "args": ["-y", "@tryfinch/finch-api-mcp"], "env": { "FINCH_ACCESS_TOKEN": "" } } } } ``` > 💡 Replace `` with a valid Finch API access token for the connection you want the LLM to access. > 🔐 **Security Note**: Use a token scoped to only the data required for your use case. Read-only tokens are recommended for most applications. Depending on your use case, and due to the sensitive nature of employment data, take extra caution when deciding what LLMs you choose to share your data with and the usage policies of the LLM provider. Finch's general recommendation is to use a self-hosted LLM for usage with the Finch MCP Server. ## Example Use Cases ### 🧑‍💼 Employee Directory Lookup **Sample Prompt:** > Find all employees in the engineering department who started after January 1st, 2023. ### 💼 Job Titles & Compensation **Sample Prompt:** > What are the current titles and base salaries of everyone on the sales team? ### 📊 Workforce Demographics **Sample Prompt:** > How many employees are full-time vs part-time across all locations? ## Need Help? If you run into issues or have questions, reach out to us at **[support@tryfinch.com](mailto:support@tryfinch.com)**. # Pay Statement Items & Rules Source: https://developer.tryfinch.com/developer-resources/Pay-Statement-Items-Rules Assign labels, categories, and metadata to pay statement items based on custom rules. ## Overview Finch allows you to define how pay statement items are processed, categorized, or modified based on custom rules. This enables more customized payroll data management and streamlined operations. You can associate specific labels, track eligibilities, or perform reconciliation depending on your needs. ## How It Works To create a rule: 1. Identify the metadata attributes that you would like to track for pay statement items (eg. item eligibility or source code). 2. Fetch all the unique pay statement items for a given connection from the /pay-statement-item endpoint to identify what the rules can be applied on for the connection. 3. Identify what the rule should be (eg. for pay statement deduction items that are called "401k", assign a label called "Pre-Tax EE Deferral"). 4. Call the Finch [POST /pay-statement-item/rules](/api-reference/payroll/create-rule) endpoint to create a rule. 5. Use the other management endpoints (GET, PUT, DEL) to maintain those rules. Once a rule has been created, Finch applies that rule for all pay statement items for that connection. When the rule conditions are met, metadata attributes will be appended to that pay statement item, which can be retrieved as part of [/pay-statement](/api-reference/payroll/pay-statement) or [/pay-statement-item](/api-reference/payroll/get-pay-statement-items) endpoints. Note that pay statement item rules can only be applied to a specific connection. Universal rules are not supported currently. ## Use Cases 1. Categorizing Pay Statement Items Automatically: You can use rules to assign labels or categories to payroll items * If the name field is "Salary", label it as "Base Compensation". * If the name field is "Bonus", label it as "Variable Pay". 2. Enforcing Deduction Policies: Automatically flag or process specific deductions * If the name field is "401k", ensure it is categorized as a pre-tax deduction. * If the name field is "HSA", add a metadata tag for tax-exempt handling. 3. Managing Employer Contributions: You can use rules to track employer contributions separately * If the name field is "Health Insurance", classify it as an employer contribution. * If the name field is "Retirement Match", ensure proper tax treatment. 4. Custom Payroll Data Processing * Apply a custom label to specific pay statement items to align with internal reporting. * Automatically reformat certain pay statement items for easier integration with reconciliation software. ## Best Practices * Use clear and specific conditions: Avoid broad conditions that may unintentionally apply to multiple pay statement items. * Test rules before production use: Validate sample pay statements to ensure rules behave as expected. * Monitor rule execution: Regularly audit payroll processing results to identify any unexpected behaviors. # Pay Statement Type Classification Source: https://developer.tryfinch.com/developer-resources/Pay-Statement-Type-Classification Learn how to classify Contributions and Deductions retrieved from the Finch Payroll endpoints. Pay statement items may need to be classified with specific types, such as 401(k), safe-harbor, HSA, etc. Finch attempts to classify individual pay statement items into four categories (Earnings, Taxes, Employer Contributions, Employee Deductions) with a specific type based on the description of the item. However, Finch may not be able to appropriately classify a contribution or deduction if there are not enough details available in the description. For example, instead of naming an item '401k plan', an employer may use an internal code '1j7dfp'. Finch is unable to classify items in this scenario. In instances when Finch is unable to classify a Contribution or Deduction, the best practice is: 1. Identify the names/descriptions that the employer has set up the Contributions or Deductions as in their payroll system 2. Have the employer go through Finch Connect, authorizing Finch to retrieve data from the payroll system 3. Retrieve pay statements for the past 2-3 months via the `/pay-statement` endpoint 4. Parse through the results to get the `employee_deductions.name` and `employer_contributions.name` 5. Create an internal mapping to associate the `name` with the appropriate Deduction or Contribution # Reauthentication Source: https://developer.tryfinch.com/developer-resources/Reauthentication Reauthenticate a connection after Finch returns a 401 reauthenticate_user error. Covers multi-entity connections, employee permissions, and scope updates. A Finch connection breaks when the authentication credentials Finch uses to access the employer's provider system no longer work. When this happens, the connection's status changes to `reauth`, and Finch returns a `401 Unauthorized` HTTP status code with a `finch_code` of `reauthenticate_user` (see [Finch API errors](/api-reference/development-guides/errors/Error-Types)). ```js theme={null} { "code": 401, "name": "authentication_error", "finch_code": "reauthenticate_user", "message": "Please reauthenticate user" } ``` If an access token returns this error, the employer must reauthenticate by completing a Finch Connect Reauthentication session. Make sure your application uses the [reauthentication session](/api-reference/connect/reauthenticate-session) endpoint with the `connection_id` instead of creating a new connection session. See [Reauthentication errors](/implementation-guide/Backend-Application/Mitigate-Errors#reauthentication-errors) for more details about this error. ## Notify the employer to reauthenticate Notify the employer as soon as a connection needs reauthentication — for example with an in-app banner or email — so they can reauthenticate before missing a data sync. Prompt them to reauthenticate through your existing Finch Connect flow, whether that's directly in your app or by sending them a link. Reauthenticating only replaces the `access_token`. Other Finch identifiers, like `individual_id` or `payment_id`, stay the same across tokens. ## Reauthenticate multi-entity connections If some entities in a multi-entity connection require reauthentication while others remain connected, developers can continue retrieving data for the entities that are still connected. Employers using a multi-entity payroll system can add additional entities during reauthentication. Finch also verifies that the reauthenticating employee has access to all entities originally connected. If the employee does not have access to one or more of those entities, the reauthentication attempt fails and Finch returns an error. To resolve this: * The employee must gain access to the missing entities in the payroll system, or * The developer uses `/disconnect-entity` to remove the entities the employee cannot access, then reauthenticates the connection for the remaining entities If an entity is in `reauth` status and the employer wants to remove it instead of reauthenticating it, use [`/disconnect-entity`](/api-reference/management/disconnect-entity) to remove that entity from the connection. The other entities and the access token are not affected. ## Reauthenticate with a different employee The employee who reauthenticates a connection does not have to be the employee who originally connected it — any employee can reauthenticate, as long as they have sufficient permissions in the payroll system to access the data the connection is authorized for. This commonly comes up when the original employee leaves the company or when their role or permissions change. If the reauthenticating employee does not have sufficient permissions, the reauthentication attempt fails and Finch returns an error. To resolve this: * The employee gains the required permissions in the payroll system, or * A different employee with sufficient permissions reauthenticates the connection instead ## Update product scopes using a reauthentication session A reauthentication session can be initiated specifically to update product scopes — the connection does not need to be in `reauth` status to do this. Pass the desired `products` array to [reauthenticate a session](/api-reference/connect/reauthenticate-session) to add or remove scopes on an existing connection without creating a new one. ## Add entities using a reauthentication session A reauthentication session can also be initiated to let an employer add entities to an existing connection — the connection does not need to be in `reauth` status to do this. Create a [reauthentication session](/api-reference/connect/reauthenticate-session) and prompt the employer to complete it in Finch Connect. If entities exist that aren't yet connected, the employer can select them there. After the employer completes Finch Connect, exchange the resulting authorization code through [`/auth/token`](/api-reference/management/create-access-token) as usual. The response's `entity_ids` array includes the newly added entities. Call [`/introspect`](/api-reference/management/introspect) at any time to see the full list of connected entities, including each one's `status`. # Reconcile Employees Source: https://developer.tryfinch.com/developer-resources/Reconcile-Employees Learn how to reconcile employee profiles in Finch using PII such as full name and date of birth (DOB), email, or SSN. If you have employees or contractors in your database that you need to match with Finch's `individual_id`s, you will need a reliable method to reconcile the two. The following are two best practices for developers building with Finch. ### Recommended: full name + date of birth All payroll systems require at least a first and last name, therefore, finding a match by full name is a good way of reconciling individuals. However, on rare occasions, naming collisions do happen even within the same company. Therefore, we recommend using a concatenation of `first_name`, `last_name`, and `dob`, all data points available from the `/individual` endpoint. Finch returns `first_name`, `last_name`, and `dob` for all systems we support. However, sometimes all the data points not inputted into the system by the payroll administrator of a company. We recommend confirming with your customer that the data points are inputted into the system for all employees before reconciliation. ### Alternative: email address Finch returns email addresses from the `/individual` endpoint. The uniqueness of emails, *if they are returned by the underlying employment system*, makes it a good data point to reconcile employees against. Finch's API does not always return emails. We find `first_name`, `last_name`, and `dob` are more consistent than `email`s. ### Alternative: Social Security Number Finch returns Social Security Number (SSN) of an individual, which can be helpful in identifying unique individuals. However, SSN is not returned by default since it is a sensitive field; you must [enable SSN](/developer-resources/Enable-SSN-Field) for your application first. # Request Forwarding Source: https://developer.tryfinch.com/developer-resources/Request-Forwarding Finch Request Forwarding is a passthrough API feature that enables you to issue raw requests directly against an employment system’s API. ## Enabling Custom Data Requests With Request Forwarding, you have the ability to access any functionality that is natively supported by an integration, including data elements that are outside of Finch's existing API structure and standard data model. You’ll also be able to write data elements that are outside the scope of what is supported through one of Finch's standardized APIs. Request Forwarding is only available to customers on a Pro or Premier plan. To enable Request Forwarding for your account, reach out to your Developer Success Representative or email [developers@tryfinch.com](mailto:developers@tryfinch.com). ### Using Request Forwarding You can [watch a video demonstration](https://www.loom.com/share/15ca7fb93c2d43b9a052362fd3368e37) that exhibits how to use the [/forward](/developer-resources/Request-Forwarding) API for accessing deeper data sets within an employment system. ### How it Works **Standard Finch API Request** - Requests to one of Finch's standard API endpoints go through a data transformation layer to ensure that you have a consistent request and response structure to work with, regardless of the system you’re extracting data from. finch_standard_api.png **Finch Request Forwarding** - Request Forwarding bypasses the data transformation layer, giving you access to the raw data exposed by an integration and leaving the data mapping fully in your control. finch_request_forwarding.png ### Why Request Forwarding? For each supported integration, Finch provides a standardized set of API endpoints and data models. However, if you require additional information outside these standard models, Request Forwarding enables your application to read or write specific fields from provider-supported API endpoints. This supplements Finch's standardized endpoints and fields without you needing to handle the complexities of building and managing a separate integration yourself for accessing non-standardized fields. For example, consider a situation where Finch's data model supports 95% of the fields your application needs. Instead of having to build a direct integration with the provider to get the other 5% of fields you need, you can look to Request Forwarding. After all, building and maintaining a single integration is the reason you chose Finch in the first place! With Request Forwarding, you can gain access to the other 5% of the data you need. When using Request Forwarding, Finch leverages the existing connection that was established via Finch Connect, forwards the request to the provider, and then forwards the provider's response back to your application. It is important to note that Request Forwarding does not alter requests or responses, it simply forwards them between you and the provider while Finch manages credentials and authentication for you. ### Supported Integrations The integrations and associated API documentation for the systems that are currently supported by Request Forwarding are referenced below. In order to use Request Forwarding for a particular provider you must ensure that connections are established using the appropriate [authentication method](/how-finch-works/unified-employment-api-glossary#authentication-method). | **Integration** | **Authentication Method** | **API Documentation** | | ------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BambooHR | `oauth` | [https://documentation.bamboohr.com/reference](https://documentation.bamboohr.com/reference) | | Factorial HR | `oauth` | [https://apidoc.factorialhr.com/reference](https://apidoc.factorialhr.com/reference) | | Gusto | `oauth` | [https://docs.gusto.com/app-integrations/reference](https://docs.gusto.com/app-integrations/reference) | | HiBob | `credential` `api_token` | [https://apidocs.hibob.com/reference](https://apidocs.hibob.com/reference) | | Justworks | `oauth` | [https://public-api.justworks.com/v1/docs](https://public-api.justworks.com/v1/docs) | | Paycom | `api_token` | [https://drive.google.com/file/d/1aC9C4W1mZo4oFxNIZUtS1zkfJ4tH6WjD/view?usp=sharing](https://drive.google.com/file/d/1aC9C4W1mZo4oFxNIZUtS1zkfJ4tH6WjD/view?usp=sharing) | | Personio | `api_token` | [https://developer.personio.de/reference](https://developer.personio.de/reference) | | Rippling | `oauth` | [https://developer.rippling.com/documentation/base-api](https://developer.rippling.com/documentation/base-api) | | TriNet | `api_token` | [https://developers.trinet.com/explore-trinet-apis](https://developers.trinet.com/explore-trinet-apis) | | UKG Pro | `api_token` | [https://developer.ukg.com/hcm/reference/welcome-to-the-ukg-pro-api](https://developer.ukg.com/hcm/reference/welcome-to-the-ukg-pro-api) | | Workday1 | `api_token` | [https://community.workday.com/sites/default/files/file-hosting/productionapi/index.html](https://community.workday.com/sites/default/files/file-hosting/productionapi/index.html) | | UKG Ready | `api_token` | [https://secure7.saashr.com/ta/docs/rest/public/](https://secure7.saashr.com/ta/docs/rest/public/) | 1 See details on making Workday requests using Request Forwarding [here](/integrations/guides/workday-request-forwarding). ### Example Usage Let's walk through a simple example use case for Request Forwarding. Let's say you want to access the termination details for an inactive individual in an HRIS system. Finch's [/employment](/api-reference/organization/employment) data model includes information related to an individual's employment, such as their name, title, department, start and end date, and employment status, but does not include information specific to their termination, such as the reason for their termination. In this example, we illustrate how to use Request Forwarding with an active **Personio** connection to access the **termination reason** for an inactive individual by the name of **Myriam Smith**. **Step 1:** Make a request to Finch's **/directory** endpoint to gather details of this company's employee directory. Request: ```bash theme={null} curl --location 'https://api.tryfinch.com/employer/directory' \ --header 'Authorization: Bearer {{FINCH_ACCESS_TOKEN}}' \ --header 'Content-Type: application/json' \ --header 'Finch-API-Version: 2020-09-17' ``` Response: ```bash theme={null} { "paging": { "count": 148, "offset": 0 }, "individuals": [ { "id": "51834db6-94e4-4e34-bc5d-76bc8456fb55", "first_name": "Myriam", "last_name": "Smith", "middle_name": null, "department": { "name": "Customer Service" }, "manager": { "id": "8b59db87-1b44-4a84-82f4-763885e2b99b" }, "is_active": false }, [...], { "id": "ed535ff8-6f61-4756-8cb9-edba67c87766", "first_name": "Yajaira", "last_name": "Borton", "middle_name": null, "department": { "name": "HR" }, "manager": { "id": "03ab76b5-d158-4c7f-aaf6-a82894e66790" }, "is_active": true } ] } ``` **Step 2:** Given the individual's unique ID, make a request to Finch's **/employment** endpoint to gather holistic details of their employment. Request: ```bash theme={null} curl --location 'https://api.tryfinch.com/employer/employment' \ --header 'Authorization: Bearer {{FINCH_ACCESS_TOKEN}}' \ --header 'Content-Type: application/json' \ --header 'Finch-API-Version: 2020-09-17' \ --data '{ "requests": [ { "individual_id": "51834db6-94e4-4e34-bc5d-76bc8456fb55" } ] } ' ``` Response: ```bash theme={null} { "responses": [ { "individual_id": "51834db6-94e4-4e34-bc5d-76bc8456fb55", "code": 200, "body": { "id": "51834db6-94e4-4e34-bc5d-76bc8456fb55", "first_name": "Myriam", "last_name": "Smith", "middle_name": null, "title": "IT-Customer Service Manager", "employment": { "type": "employee", "subtype": null }, "manager": { "id": "8b59db87-1b44-4a84-82f4-763885e2b99b" }, "department": { "name": "Customer Service" }, "start_date": "2014-11-01", "end_date": "2020-11-30", "is_active": false, "class_code": null, "location": null, "income": { "unit": "monthly", "amount": 412500, "currency": "SEK", "effective_date": null }, "income_history": null, "custom_fields": [ { "name": "Trainings", "value": "Data security training,Product training" }, { "name": "Marital status", "value": "single" }, { "name": "Language Skills", "value": "English,German" } ], "source_id": "12907776" } } ] } ``` **Step 3:** Given the `source_id` field in Finch's /employment response, use the **/forward** endpoint to access additional details directly from Personio's API, including this individual's `termination_reason`. Request: ```bash theme={null} curl --location 'https://api.tryfinch.com/forward' \ --header 'Authorization: Bearer {{FINCH_ACCESS_TOKEN}}' \ --header 'Content-Type: application/json' \ --header 'Finch-API-Version: 2020-09-17' \ --data '{ "method": "GET", "route": "/company/employees/12907776", "headers": null, "params": null, "data": null } ' ``` Response: ```bash theme={null} { "request": { "headers": null, "method": "GET", "route": "/company/employees/12907776", "data": null, "params": null }, "headers": { "date": "Wed, 04 Oct 2023 20:21:27 GMT", "content-type": "application/json", "transfer-encoding": "chunked", "connection": "close", "x-is-preview": "false", "x-is-shadow": "false", "vary": "Accept-Encoding, Origin", "cache-control": "no-cache, private", "content-security-policy": "frame-ancestors 'none'", "strict-transport-security": "max-age=31536000", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff" }, "statusCode": 200, "data": "{\"success\":true,\"data\":{\"type\":\"Employee\",\"attributes\":{\"id\":{\"label\":\"ID\",\"value\":12907776,\"type\":\"integer\",\"universal_id\":\"id\"},\"first_name\":{\"label\":\"First name\",\"value\":\"Myriam\",\"type\":\"standard\",\"universal_id\":\"first_name\"},\"last_name\":{\"label\":\"Last name\",\"value\":\"Smith\",\"type\":\"standard\",\"universal_id\":\"last_name\"},\"email\":{\"label\":\"Email\",\"value\":\"myriam.smith@demo-sample.com\",\"type\":\"standard\",\"universal_id\":\"email\"},\"gender\":{\"label\":\"Gender\",\"value\":\"female\",\"type\":\"standard\",\"universal_id\":\"gender\"},\"status\":{\"label\":\"Status\",\"value\":\"inactive\",\"type\":\"standard\",\"universal_id\":\"status\"},\"position\":{\"label\":\"Position\",\"value\":\"IT-Customer Service Manager\",\"type\":\"standard\",\"universal_id\":\"position\"},\"supervisor\":{\"label\":\"Supervisor\",\"value\":{\"type\":\"Employee\",\"attributes\":{\"id\":{\"label\":\"ID\",\"value\":12907741,\"type\":\"integer\",\"universal_id\":\"id\"},\"first_name\":{\"label\":\"First name\",\"value\":\"Max\",\"type\":\"standard\",\"universal_id\":\"first_name\"},\"last_name\":{\"label\":\"Last name\",\"value\":\"Schmiedel\",\"type\":\"standard\",\"universal_id\":\"last_name\"},\"email\":{\"label\":\"Email\",\"value\":\"max.schmiedel@demo-sample.com\",\"type\":\"standard\",\"universal_id\":\"email\"}}},\"type\":\"standard\",\"universal_id\":\"supervisor\"},\"employment_type\":{\"label\":\"Employment type\",\"value\":\"internal\",\"type\":\"standard\",\"universal_id\":\"employment_type\"},\"weekly_working_hours\":{\"label\":\"Weekly hours\",\"value\":\"40\",\"type\":\"standard\",\"universal_id\":\"weekly_working_hours\"},\"hire_date\":{\"label\":\"Hire date\",\"value\":\"2014-11-01T00:00:00+01:00\",\"type\":\"date\",\"universal_id\":\"hire_date\"},\"contract_end_date\":{\"label\":\"Contract ends\",\"value\":null,\"type\":\"date\",\"universal_id\":\"contract_end_date\"},\"termination_date\":{\"label\":\"Termination date\",\"value\":\"2020-11-30T00:00:00+01:00\",\"type\":\"date\",\"universal_id\":\"termination_date\"},\"termination_type\":{\"label\":\"Termination type\",\"value\":\"employee-quit\",\"type\":\"standard\",\"universal_id\":\"termination_type\"},\"termination_reason\":{\"label\":\"Termination reason\",\"value\":\"employee-quit\",\"type\":\"standard\",\"universal_id\":\"termination_reason\"},\"probation_period_end\":{\"label\":\"Probation period end\",\"value\":\"2015-04-30T00:00:00+02:00\",\"type\":\"date\",\"universal_id\":\"probation_period_end\"},\"created_at\":{\"label\":\"Created at\",\"value\":\"2020-09-21T10:48:14+02:00\",\"type\":\"date\",\"universal_id\":\"created_at\"},\"last_modified_at\":{\"label\":\"Last modified\",\"value\":\"2022-12-09T17:34:50+01:00\",\"type\":\"date\",\"universal_id\":\"last_modified_at\"},\"subcompany\":{\"label\":\"Subcompany\",\"value\":{\"type\":\"Subcompany\",\"attributes\":{\"id\":127825,\"name\":\"Subsidiary SE\"}},\"type\":\"standard\",\"universal_id\":\"subcompany\"},\"office\":{\"label\":\"Office\",\"value\":{\"type\":\"Office\",\"attributes\":{\"id\":1466964,\"name\":\"Gothenburg\"}},\"type\":\"standard\",\"universal_id\":\"office\"},\"department\":{\"label\":\"Department\",\"value\":{\"type\":\"Department\",\"attributes\":{\"id\":3853110,\"name\":\"Customer Service\"}},\"type\":\"standard\",\"universal_id\":\"department\"},\"cost_centers\":{\"label\":\"Cost center\",\"value\":[{\"type\":\"CostCenter\",\"attributes\":{\"id\":730214,\"name\":\"Cost center 2\",\"percentage\":100}}],\"type\":\"standard\",\"universal_id\":\"cost_centers\"},\"holiday_calendar\":{\"label\":\"Public holidays\",\"value\":{\"type\":\"HolidayCalendar\",\"attributes\":{\"id\":2015,\"name\":\"Sweden public holidays\",\"country\":null,\"state\":null}},\"type\":\"standard\",\"universal_id\":\"holiday_calendar\"},\"absence_entitlement\":{\"label\":\"Absence entitlement\",\"value\":[{\"type\":\"TimeOffType\",\"attributes\":{\"id\":2135006,\"name\":\"Paid Vacation UK\",\"category\":\"paid_vacation\",\"entitlement\":0}},{\"type\":\"TimeOffType\",\"attributes\":{\"id\":2135005,\"name\":\"Paid Vacation SE\",\"category\":\"paid_vacation\",\"entitlement\":0}},{\"type\":\"TimeOffType\",\"attributes\":{\"id\":2135004,\"name\":\"Paid Vacation NL\",\"category\":\"paid_vacation\",\"entitlement\":0}}],\"type\":\"standard\",\"universal_id\":\"absence_entitlement\"},\"work_schedule\":{\"label\":\"Work schedule\",\"value\":{\"type\":\"WorkSchedule\",\"attributes\":{\"id\":1248089,\"name\":\"Full-time, 40 hours without time tracking, (mon,tue,wed,thu,fri)\",\"valid_from\":null,\"monday\":\"08:00\",\"tuesday\":\"08:00\",\"wednesday\":\"08:00\",\"thursday\":\"08:00\",\"friday\":\"08:00\",\"saturday\":\"00:00\",\"sunday\":\"00:00\"}},\"type\":\"standard\",\"universal_id\":\"work_schedule\"},\"fix_salary\":{\"label\":\"Fixed salary\",\"value\":4125,\"type\":\"decimal\",\"universal_id\":\"fix_salary\",\"currency\":\"SEK\"},\"fix_salary_interval\":{\"label\":\"Salary interval\",\"value\":\"monthly\",\"type\":\"standard\",\"universal_id\":\"fix_salary_interval\"},\"hourly_salary\":{\"label\":\"Hourly salary\",\"value\":0,\"type\":\"decimal\",\"universal_id\":\"hourly_salary\",\"currency\":\"SEK\"},\"vacation_day_balance\":{\"label\":\"Vacation day balance\",\"value\":0,\"type\":\"decimal\",\"universal_id\":\"vacation_day_balance\"},\"last_working_day\":{\"label\":\"Last day of work\",\"value\":null,\"type\":\"date\",\"universal_id\":\"last_working_day\"},\"profile_picture\":{\"label\":\"Profile Picture\",\"value\":\"https://api.personio.de/v1/company/employees/12907776/profile-picture\",\"type\":\"standard\",\"universal_id\":\"profile_picture\"},\"team\":{\"label\":\"Team\",\"value\":{\"type\":\"Team\",\"attributes\":{\"id\":1674017,\"name\":\"Customer Service\"}},\"type\":\"standard\",\"universal_id\":\"team\"},\"dynamic_6726179\":{\"label\":\"Type of Visa\",\"value\":\"\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726181\":{\"label\":\"Employee ID\",\"value\":\"11617\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726182\":{\"label\":\"National Insurance Number\",\"value\":\"99999999999\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726188\":{\"label\":\"Holder of bank account\",\"value\":\"Myriam Smith\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726191\":{\"label\":\"Emergency contact name\",\"value\":\"Sabina Smith\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726195\":{\"label\":\"Address\",\"value\":\"Kössö Bryggväg 33\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726165\":{\"label\":\"Birthday\",\"value\":\"1988-05-10T00:00:00+02:00\",\"type\":\"date\",\"universal_id\":\"date_of_birth\"},\"dynamic_6726173\":{\"label\":\"Trainings\",\"value\":\"Data security training,Product training\",\"type\":\"tags\",\"universal_id\":null},\"dynamic_6726180\":{\"label\":\"Visa expiry date\",\"value\":null,\"type\":\"date\",\"universal_id\":null},\"dynamic_6726189\":{\"label\":\"IBAN\",\"value\":\"SE45 5000 0000 0583 9825 7490\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726193\":{\"label\":\"Marital status\",\"value\":\"single\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726197\":{\"label\":\"City\",\"value\":\"Gothenburg\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726203\":{\"label\":\"Company car\",\"value\":\"\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726175\":{\"label\":\"Language Skills\",\"value\":\"English,German\",\"type\":\"tags\",\"universal_id\":null},\"dynamic_6726186\":{\"label\":\"Type of health insurance\",\"value\":\"compulsory\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726190\":{\"label\":\"BIC\",\"value\":\"XXAADEFF\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726192\":{\"label\":\"Emergency contact phone number\",\"value\":\"(+49) 1601234567\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726196\":{\"label\":\"Postcode\",\"value\":\"405 10\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726204\":{\"label\":\"Laptop model\",\"value\":\"\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726166\":{\"label\":\"LinkedIn\",\"value\":\"https://www.linkedin.com/\",\"type\":\"link\",\"universal_id\":null},\"dynamic_6726176\":{\"label\":\"First Aider\",\"value\":\"no\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726187\":{\"label\":\"Name of health insurance\",\"value\":\"Example Insurance\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726194\":{\"label\":\"Personal email\",\"value\":\"Myriam@Smith.com\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726171\":{\"label\":\"Emergency contact relationship to the employee\",\"value\":\"mother\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726198\":{\"label\":\"Main or secondary occupation\",\"value\":\"main occupation\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726202\":{\"label\":\"Nationality\",\"value\":\"Swedish\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726199\":{\"label\":\"Child allowance\",\"value\":\"0\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726170\":{\"label\":\"Salary type\",\"value\":\"fix salary\",\"type\":\"list\",\"universal_id\":null},\"dynamic_6726168\":{\"label\":\"Notice period\",\"value\":\"3 months to end of month\",\"type\":\"standard\",\"universal_id\":null},\"dynamic_6726169\":{\"label\":\"Occupation type\",\"value\":\"permanent employment\",\"type\":\"list\",\"universal_id\":null}}}}" } ``` The /forward API response includes details of the original `request`, alongside the forwarded response details from Personio's API. The response body that was retrieved from Personio is provided in raw format in the `data` response field. Myriam's **termination\_reason** can be extracted from here. ```js theme={null} { label: 'Termination reason', value: 'employee-quit', type: 'standard', universal_id: 'termination_reason' } ``` To recap, we've illustrated an example of how to use Request Forwarding to complement Finch's standardized data models, providing you with the most comprehensive view of the data you need, without having to incur the burden of managing an additional integration, all using a single Finch access token! # SDKs Source: https://developer.tryfinch.com/developer-resources/SDKs Explore our frontend and backend SDK repositories. Finch supports SDKs in JavaScript, React, Node, Python, Java, Kotlin, Go, and Ruby. ## Frontend SDK Finch's frontend SDK allows you to [embed Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect#embedded-flow) into your application, enabling you to provide a seamless integration experience for your users. We offer both a JavaScript and React frontend SDK, both of which can be viewed at the repository below: ## Backend SDKs Finch maintains SDKs in several popular languages to make it easy to integrate with Finch APIs. These SDKs are regularly updated for breaking and non-breaking API changes. In addition to installation and quickstart information, each repository contains an `api.md` that documents available methods and data models. If you do not see your language here, reach out to us! # Tiered Employer Matching Source: https://developer.tryfinch.com/developer-resources/Tiered-Employer-Matching Learn how to manage tiered employer contributions (employer match) with Finch. A 'tiered' company match is a structure where an employer matches employee retirement contributions at different rates across “tiers” of employee deferrals. Instead of one flat match rate, the match changes once the employee’s contribution crosses certain percentage thresholds. Example > “100% of the first 3% and 50% of the next 2% of the employee’s contributions.” This means: * On the first **3%** of pay the employee contributes, the employer matches **100%** (dollar-for-dollar). * On the next **2%** of pay the employee contributes, the employer matches **50%** (50 cents on the dollar) ### Tiered Matching Examples Tiered matching is common in retirement plans like 401(k), 403(b), and similar plans. Some examples of tiered match include: * **Traditional Safe Harbor, Basic Match:** * 100% of the first 3% of compensation deferred, plus 50% of the next 2% * **Traditional Safe Harbor, Enhanced Match** * 100% of the first 4% of compensation (4% max) * 100% of the first 5% of compensation (5% max) * 100% of the first 6% of compensation (6% max) * **QACA Safe Harbor, Basic Match** * 100% of the first 1% of compensation deferred, plus 50% of the next 5% * **QACA Safe Harbor – Enhanced Match** * 100% of the first 3.5% of compensation (3.5% max) * 100% of the first 4% of compensation (4% max) * 200% of the first 2% of compensation (4% max) ## Finch Integrations that Support Tiered Matching Find the list of providers that support percent, fixed, and tiered employer matching [here](https://dashboard.tryfinch.com/docs/components/field-support?mode=dark\&group=deductions\&subgroup=features\&field=company_contribution%3Atiered%2Ccompany_contribution%3Apercent%2Ccompany_contribution%3Afixed\&endpoint=\&provider=\&authorization_type=). You can also visit our Field Support page and follow these steps: 1. From the dropdown, select **“Field Support for Deductions.”** 2. Go to the **“Supported Features for Deductions”** tab. 3. Under **“Benefit Feature,”** select all applicable options: * `company_contribution:percent` * `company_contribution:fixed` * `company_contribution:tiered` ## How to Convert a Tiered Match Into a Single Match Percentage Some payroll systems only support employer contributions as a single percentage of gross compensation (e.g., “x% of gross comp”), not as a tiered match based on employee contributions. If Finch support percentage contributions for a provider, you can convert the tiered match into a single % number to achieve the same outcome. This section explains how to calculate that single percentage per employee, for each payroll, when your plan formula is: > 100% of the first 3% of compensation deferred, and 50% of the next 2% ### Step 1: Find the employee’s contribution rate (R) Get the employee’s contribution rate (R). Note that this “conversion” works reliably for %-based employee contributions only. ### Step 2: Convert R into a single employer percentage of gross comp For this match formula (100% of first 3%, 50% of next 2%), the employer contribution as a single % of gross compensation can be found following the calculations below: Let R = employee contribution rate (%): * If R ≤ 0% → Employer % = **0%** * If 0% \< R ≤ 3% → Employer % = **R** * If 3% \< R ≤ 5% → Employer % = **3% + 0.5 × (R − 3%)** * If R > 5% → Employer % = **4%** (the maximum match) ### Examples Using the same formula (100% of first 3% and 50% of the next 2%): * Employee defers 2% of pay * Falls in the 0–3% range * Employer % = R = **2% of gross comp** * Employee defers 4% of pay * Falls in the 3–5% range * Employer % = 3% + 0.5 × (4% − 3%) * Employer % = 3% + 0.5% = **3.5% of gross comp** * Employee defers 6% of pay * Above 5%, match is capped * Employer % = **4% of gross comp** This approach gives you a single, per-employee employer contribution rate that correctly reflects the tiered match formula for each payroll period. # Webhooks Source: https://developer.tryfinch.com/developer-resources/Webhooks Finch sends account update, job completion, and data change events via webhook. Register an endpoint in the Developer Dashboard to get your webhook secret. New to Finch webhooks? Start with [Webhook Registration](/developer-resources/Webhooks#webhook-registration) to set up your endpoint and get your secret, then see [Webhook Verification](/developer-resources/Webhooks#webhook-verification) to learn how to validate incoming webhooks. Your webhook endpoint, and the secret used to verify it, must live on your backend — for the same reason your Finch access token does. See [Backend Security](/implementation-guide/Backend-Application/Backend-Security). Webhooks are not available on our legacy Free or Build plans. [Upgrade](https://www.tryfinch.com/pricing) 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 Name | Type | Description | | --------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `company_id` | string\ | Unique Finch ID of the company for which data has been updated. | | `account_id` | string\ | **Deprecated.** Use `connection_id` instead. | | `connection_id` | string\ | 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_id` | string\ | 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_type` | string | The type of webhook being delivered. | | `data` | object | More 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 Name | Type | Description | | ---------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event_type` | string | Always `account.updated`. | | `data.status` | string | The 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_method` | string | The method of authentication used to connect this account. Options follow the standard Finch authentication types: `credential`, `api_token`, `oauth`, and `assisted`. | Example: ```json theme={null} { "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. | Event | Description | Values | | ------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `job.data_sync_all.completed` | Emitted for automated data sync jobs. Check status via the automated jobs endpoint. | — | | `job.w4_form_employee_sync.completed` | Emitted for automated W4 form sync jobs. Check status via the automated jobs endpoint. | — | | `job.initial_data_sync_*.succeeded` | Emitted when an initial data sync completes successfully for the first time. | `initial_data_sync_org`, `initial_data_sync_payroll` | | `job.benefit_*.completed` | Emitted 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 Name | Type | Description | | -------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event_type` | string | Follows 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_id` | string\ | The id of the job which has completed. | | `data.job_url` | string | The url to query the result of the job. | Example: ```json theme={null} { "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 Name | Type | Description | | ------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event_type` | string | Follows 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](https://dashboard.tryfinch.com/login). | | `data` | object | The data object schema will change depending on the endpoint. | The possible `data` schemas per endpoint are as follows: | Endpoint | Event types | `data` fields | | --------------- | ------------------------------------------------------------------------- | ----------------------------- | | `company` | `company.updated` only | `null` | | `directory` | `directory.created`, `directory.updated`, `directory.deleted` | `individual_id` | | `employment` | `employment.created`, `employment.updated`, `employment.deleted` | `individual_id` | | `individual` | `individual.created`, `individual.updated`, `individual.deleted` | `individual_id` | | `payment` | `payment.created`, `payment.updated`, `payment.deleted` | `payment_id`, `pay_date` | | `pay_statement` | `pay_statement.created`, `pay_statement.updated`, `pay_statement.deleted` | `payment_id`, `individual_id` | Examples: ```json Company theme={null} { "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" } ``` ```json Individual theme={null} { "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" } ``` ```json Pay Statement theme={null} { "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 | Event | Automated | Assisted | | --------------- | ---------- | ----------------- | | Account Updates | ✓ | ✓ | | Job Completion | All events | Benefit jobs only | | Data Changes | ✓ | — | ## Required Events The following events cover the core connection lifecycle. Which ones apply depends on your product scopes: | Event | When to handle | Action | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `account.updated` | `data.status` is `reauth` | Prompt the employer to re-authenticate via Finch Connect. See [Reauthentication](/developer-resources/Reauthentication). | | `job.initial_data_sync_org.succeeded` | Initial org data sync completes — applies if your application uses `company`, `directory`, `individual`, or `employment` | Begin reading org endpoints. Requests made before this event may return `202` or `500`. | | `job.initial_data_sync_payroll.succeeded` | Initial payroll data sync completes — applies if your application uses `payment` or `pay_statement` | Begin reading payroll endpoints. Requests made before this event may return `202` or `500`. | | `job.benefit_*.completed` | A benefit write job finishes — applies if your application uses `benefits` | Call [Retrieve a Manual Job](/api-reference/management/retrieve-a-manual-job) with `data.job_id` to check the outcome — the event fires on both success and failure. | ## Webhook Registration Webhook endpoints should use HTTPS and expect to receive POST requests with the following headers: ```json theme={null} { "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](https://dashboard.tryfinch.com/). 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. ```text theme={null} v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= v1,bm9ldHUjKzFob2VudXRob2VodWUzMjRvdWVvdW9ldQo= v2,MzJsNDk4MzI0K2VvdSMjMTEjQEBAQDEyMzMzMzEyMwo= ``` 2. **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. ```javascript Javascript theme={null} 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"); ``` ```python Python theme={null} import hmac import base64 signedContent = f"{webhook_id}.{webhook_timestamp}.{body}" SECRET = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH" # base64 decode the secret before use secretBytes = base64.b64decode(SECRET) signature = base64.b64encode( hmac.new( secretBytes, signedContent.encode(), 'sha256' ).digest() ).decode() ``` ```java Java theme={null} import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; public class Main { public static void main(String[] args) throws Exception { String signedContent = webhook_id + "." + webhook_timestamp + "." + body; String SECRET = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"; // Need to base64 decode the secret byte[] secretBytes = Base64.getDecoder().decode(SECRET); Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(secretBytes, "HmacSHA256"); sha256_HMAC.init(secret_key); byte[] rawHmac = sha256_HMAC.doFinal(signedContent.getBytes(StandardCharsets.UTF_8)); // base64 encode the result String signature = Base64.getEncoder().encodeToString(rawHmac); System.out.println(signature); } } ``` 3. **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](https://en.wikipedia.org/wiki/Replay_attack). The [Finch Backend SDKs](/developer-resources/SDKs) encapsulate all of this logic to simplify the webhook verification process. ```javascript Javascript (express.js) theme={null} 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 }); }); ``` ```python Python (FastAPI) theme={null} from finch import Finch ... @app.post('/webhooks/finch') async def handler(request: Request): body = await request.body() # raw JSON string sent from the server secret = os.environ['FINCH_WEBHOOK_SECRET'] # env var used by default; explicit here. client = Finch() payload = client.webhooks.unwrap(body, request.headers, secret) print(payload) return {'ok': True} ``` ```java Java (SpringBoot) theme={null} import com.tryfinch.api.client.FinchClient; import com.tryfinch.api.client.okhttp.FinchOkHttpClient; ... @RestController public class WebhookController { @PostMapping("/webhooks/finch") public HttpStatus handleWebhook(HttpServletRequest request, @RequestBody String payload) { try { FinchClient finch = FinchOkHttpClient.builder().webhookSecret("your-secret").build(); // Implement this to get headers from request as a ListMultimap ListMultimap headers = this.getHeadersFromRequest(request); // Validate signature finch.webhooks().verifySignature(payload, headers, null); // Implement this to handle webhook payload this.handleWebhookPayload(payload); } catch (Exception e) { // Handle exception return HttpStatus.INTERNAL_SERVER_ERROR; } return HttpStatus.OK; } } ``` ```kotlin Kotlin (SpringBoot) theme={null} import com.tryfinch.api.client.FinchClient import com.tryfinch.api.client.okhttp.FinchOkHttpClient ... @RestController class WebhookController { @PostMapping("/webhooks/finch") fun handleWebhook(request: HttpServletRequest, @RequestBody payload: String): HttpStatus { try { val finch = FinchOkHttpClient.builder().webhookSecret("your-secret").build() // Implement this function to get headers from request as a ListMultimap val headers = getHeadersFromRequest(request) // Validate signature finch.webhooks().verifySignature(payload, headers, null) // Implement this to handle webhook payload handleWebhookPayload(payload) } catch (e: Exception) { // Handle exception return HttpStatus.INTERNAL_SERVER_ERROR } return HttpStatus.OK } } ``` ```go Go (net/http) theme={null} import ( finchgo "github.com/Finch-API/finch-api-go" ... ) func webhookHandler(w http.ResponseWriter, r *http.Request) { header := r.Header secret := os.Getenv("FINCH_WEBHOOK_SECRET") now := time.Now() b, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } client := finchgo.NewClient() err = client.Webhooks.VerifySignature([]byte(b), header, secret, now) if err != nil { fmt.Println("Error with signature") os.Exit(1) } fmt.Fprintf(w, "Response to finch webhook") } func TestAppServer() { http.HandleFunc("/webhooks/finch", webhookHandler) log.Fatal(http.ListenAndServe(":8081", nil)) } ``` ## 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 ### Pair Webhooks with a Recurring Sync No webhook system can guarantee delivery. Network issues, service outages, and exhausted retries can all result in a missed event. Alongside webhooks, schedule a recurring job that reads the Finch endpoints your application uses. This keeps every connection up to date, including [assisted](/integrations/integration-types#assisted-integrations) connections, which do not emit data change events. See [Data Syncs](/developer-resources/Data-Syncs#ongoing-data-syncs) for how often Finch refreshes data. ### 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](/implementation-guide/Connect/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. # API Changes and Updates Source: https://developer.tryfinch.com/developer-resources/api-changes Keep track of changes and upgrades to the Finch API At Finch, we are committed to ensuring API stability. We design our APIs with backward compatibility in mind, and we want to make it clear what types of changes we consider non-breaking - changes that should not impact existing client integrations. This page outlines the changes we may introduce without a new API version or advance warning. ### Additive Changes * Adding new optional request fields: We may introduce new fields that are not required. Your existing requests will continue to work as-is. * Adding new response fields: You may start seeing additional fields in API responses. These will not change the structure of existing fields and can be safely ignored by clients that don’t use them. * Introducing new endpoints: New endpoints do not interfere with existing functionality. * Adding new enum values: If you're using enums, we may add new values. Make sure your implementation doesn’t break when unknown enum values are returned. * Adding new errors: New error types and codes can be added to accurately indicate the success or failure of a task. These will not change existing errors. ### Documentation Updates * Clarifying descriptions: We may refine or clarify descriptions, usage examples, or error codes in our documentation. * Improving examples or formatting: These changes help improve readability and developer experience, but do not impact functionality. ### Performance Upgrades * Improving response time: Backend optimizations or caching mechanisms that improve performance without changing behavior. * Upgrading infrastructure: These are internal changes and do not affect how the API behaves or how it should be used. To ensure your integration with Finch is as robust as possible, we recommend: * Use tolerant JSON parsers that ignore unknown fields * Don’t rely on the exact order of response fields * Make your code resilient to new enum values or unexpected optional fields # How the Finch API is organized Source: https://developer.tryfinch.com/how-finch-works/data-model Finch's API data model normalizes payroll, HR, and benefits data from 250+ providers. Walk through the core entities and how they connect in one map. The diagrams below give you a working mental model of the Finch API. Each section explains the high-level functionality of Finch's products, each of which contains multiple endpoints. ## Organization: company, individual, and employment Company maps one-to-many to Individual and Employment, which share an individual_id A Finch [connection](/implementation-guide/Backend-Application/Manage-Connections) typically covers one [Company](/api-reference/organization/company), which can include one or many entities (separate EINs, divisions, or subsidiaries) with one or many employees. Each employee has two records that share the same `individual_id`: an [Individual](/api-reference/organization/individual) record for identity data (name, DOB, SSN, home address) and an [Employment](/api-reference/organization/employment) record for job data (title, manager, start date, income). Querying them separately means you can pull only what you need. To enumerate everyone at a connection, call [`GET /employer/directory`](/api-reference/organization/directory) first. It returns a paginated list of `individual_id`s you can then fetch in detail via the endpoints above. The same person can have multiple Employment records over time (rehires, role changes, multi-EIN setups). Treat `individual_id` as the stable identity key and Employment as historical job state. ## Payroll: payments and pay statements Payment contains pay statements, which contain earnings, taxes, employee deductions, and employer contributions, all flattened into pay statement items A [Payment](/api-reference/payroll/payment) is one payrun, and it's the starting point for all payroll data. Each Payment contains one [Pay Statement](/api-reference/payroll/pay-statement) per person, broken down into earnings (base, overtime, bonus), taxes (federal, state, FICA), employee deductions (401k, health premiums, FSA), and employer contributions (401k match, employer-paid benefits). Deductions and contributions live in separate fields on the Pay Statement so you can read or aggregate each side cleanly. Use the [Pay Statement Item](/api-reference/payroll/get-pay-statement-items) endpoint to retrieve all payroll items that have appeared in a company's processed payroll, including taxes, deductions, earnings, and employer contributions. For example, if your customer's organization labels a health deduction as `EE_MED_PPO_PREM` in the provider system, this endpoint surfaces that name alongside its category and type. From there you can use the [Rules endpoint](/api-reference/payroll/get-rules) to apply the right labels and context in your system. ## Deductions: company benefits and per-employee contributions Company deduction maps to per-individual deduction records, which are referenced by pay statement items as deduction or contribution lines Finch's [Deductions](/products/deductions/Overview) product represents benefits from the payroll side, in two connected views. A company-level deduction defines the benefit at the company: type (401k, HSA, FSA, etc.), frequency, and the employer's contribution rule. An [individual deduction record](/api-reference/deductions/get-enrolled-individuals) then holds the per-person amounts: employee contribution, employer contribution, and annual maximum. The per-paycheck amount itself lives on the Pay Statement Item. The deduction record tells you what should happen each pay period; the pay statement item tells you what actually happened. You can [add individuals to a deduction](/api-reference/deductions/enroll-individuals-in-deductions), [update contribution amounts](/api-reference/deductions/update-deduction), and [remove individuals](/api-reference/deductions/unenroll-individuals-from-deductions) where the provider allows it. Call the [`/providers`](/api-reference/management/providers) endpoint to see which deduction types and operations each provider supports before you build against them. ## Benefits: plans, enrollments, and dependents Benefits is in closed beta. Endpoint paths and field names are subject to change before general availability. Plan maps one-to-many to Enrollment records, which link bidirectionally to Dependent records [Benefits](/products/benefits/Overview) is Finch's source-of-truth product for benefits enrollment. Where Deductions (above) shows the payroll-side evidence of a benefit, like what's being withheld each paycheck, Benefits returns the canonical plan and enrollment data directly from the benefits administration side of the employer's system: * **Plan**: the company-level benefit plan, including type, carrier, plan year, deduction code, and available coverage tiers. * **Enrollment**: the individual's actual enrollment in a plan, with coverage tier, effective dates, contribution amounts, and covered dependents. * **Dependent**: a spouse or child covered under an individual's enrollment, linked back to its enrollment records. Use Benefits when you need authoritative enrollment state, for example to verify coverage before quoting a benefit or to retrieve dependent details for compliance. Use Deductions when you need to see what's actually being withheld each pay period. The two are complementary. ## Documents: parsed data from HR forms Queue a job leads to a documents list, then drill into a specific document to read parsed fields Finch's [Documents](/products/documents/Overview) product reads structured data out of HR documents using ML-based parsing. Two endpoints carry the data: [`GET /employer/documents`](/api-reference/documents/get-documents) returns a list of available documents (filterable by individual or document type), and [`GET /employer/documents/{document_id}`](/api-reference/documents/get-document) returns the parsed fields for one document. Documents is async. Before either read endpoint will return fresh data, queue an automated job with [`POST /jobs/automated`](/api-reference/management/enqueue-a-new-automated-job) so Finch can sync from the provider. The product is currently in beta with W-4 support; expect more document types over time. ## Next steps Mint a sandbox token and pull your first employer record. Every endpoint, request shape, and response field. Test the data model with realistic fixtures before wiring up production. Reference for every term used across the Finch API. # Connect an Employer Source: https://developer.tryfinch.com/how-finch-works/finch-connect Finch Connect is an embedded onboarding flow that enables employers to connect their HR or payroll system to your app. In order to receive data from any employment system, you'll first need to connect an employer. Finch Connect is an embedded onboarding flow that enables employers to connect their data through the following steps. See our [Implementation Guide](/implementation-guide/go-live-checklist) for more detailed instructions on how to [set up Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect). Open Finch Connect Employers access Finch Connect from within your application. We suggest launching Finch Connect during the employer onboarding process. There are many ways to [Increase Employer Adoption](/implementation-guide/Deploy-and-Manage/Increase-Employer-Adoption) of Finch Connect. Finch Connect Screens * **Read privacy disclosures** - Finch Connect discloses data privacy practices right from the start, so your customers know where and how their data is used. * **Confirm permissions** - Finch Connect displays the granular permissions needed to access the requested data. Finch only shares data that has been approved. * **Select a provider** - Your customer can then select their employment system from Finch's list of 200+ integrations. * **Authenticate access** - Finch Connect prompts your customer to log in to their employment system, and grant you access to requested data. Finch Connect will only succeed if the user is an employer admin with permissions to view the full employee directory and view the full company payroll. Finch Connect Screens That's it! Upon successful authentication, Finch Connect closes and redirects back to your application. Once the connection is established, you will receive a Finch access token and can call the Finch API. At this point you can assure your users that the connection has been set up successfully, and redirect them to other tasks. ## Learn More More information about how Finch Connect works and how to implement it into your application can be found in the [Set Up Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) of the Finch Implementation Guide. # What is Finch? Source: https://developer.tryfinch.com/how-finch-works/finch-overview The Finch API powers integrations to employment systems through a single, standardized data model. Finch is a connectivity platform that enables you to connect to hundreds of employment systems through a unified API. Once Finch is integrated into your application, you can access your customers' company details, employment history, employee count, individual contact information, income details, company pay periods, and individual paycheck details like earnings, taxes, deductions, and contributions. Finch works by allowing your customers (employers) to connect their employment systems (HRIS, Payroll, etc.) to your application. This connection process is facilitated through [Finch Connect](/how-finch-works/finch-connect), our employer-facing user interface which provides an elegant and secure authorization flow where your customers (employers) approve permissions, select their provider, and authorize access to their employment systems. Upon a successful connection, Finch will issue an access token to your application which is used to make API requests to Finch API endpoints. How Finch Works Diagram ## Products Finch offers four products: Organization, Payroll, Deductions, and Documents. Each product has its own set of endpoints, which provide specific data related to HRIS and payroll employment systems. * Our [Organization](/products/organization/Overview) product provides APIs to read company directory and employee data including contact information, demographics, departmental hierarchy, income history, and more. * Our [Payroll](/products/payroll/Overview) product provides APIs for retrieving company payroll and inspecting individual paycheck information such as earnings, taxes, deductions, and contributions. * Our [Deductions](/products/deductions/Overview) product provides APIs for creating, enrolling, and unenrolling individuals in deductions and contributions directly within the payroll provider. * Our [Documents](/products/documents/Overview) product provides APIs to read data from employee and employer documents like W-4 forms. ## Finch Connect Employers connect their data to your application in 4 easy steps, facilitated through [Finch Connect](/how-finch-works/finch-connect). * **Prioritize privacy**: Finch Connect discloses data privacy practices right from the start, so your customers know where and how their data is used. * **Confirm permissions**: Finch Connect displays the granular permissions needed to access the requested data. Finch only shares data that has been approved. * **Select a provider**: Once the user approves, they select their employment system from Finch's list of 200+ integrations. * **Authenticate access**: The user is prompted to log into their account (via credentials or API key if available), granting your application access to their employment data. ## Integration Types Finch offers two [Integration Types](/integrations/integration-types) that enable you to optimize for either data refresh cadence or long-tail provider coverage. This allows you to service *all* of your customers via Finch, no matter which employment systems they are using. Employers will go through different Finch Connect experiences depending on the integration type. ## Connections After an employer authenticates via Finch Connect, a connection is established between you and the employer via Finch. A [connection](/how-finch-works/unified-employment-api-glossary#connection) is a unique *Provider* + *App* + *Company* pairing. # Quickstart Source: https://developer.tryfinch.com/how-finch-works/quickstart This API Quickstart guide will help you send your first request to Finch, the unified API for HR and payroll. To get started, sign up for a sandbox account [here](https://dashboard.tryfinch.com/signup). After registration, you will have access to a sandbox application `client_id` and `client_secret` to build and test how Finch works using simulated data. This guide will help you send your first request to Finch's API while the following guides dive deeper into the concepts and help you integrate Finch into your production application. ## Open Finch Connect in sandbox mode Finch Connect provides a secure and elegant authorization flow for your users to grant your application access to their systems. Note: this quickstart guide is a simplified, but manual way of generating an authorization `code` and exchanging it for an `access_token`, which can be used to subsequently call our APIs. In a true production environment, you will want to automate this process completely inside your application's code. Since this quickstart assumes you have not built an application yet, we must make sure that a proper `redirect_uri` is set up before continuing or our authorization code generation will fail. In your [Finch Dashboard](https://dashboard.tryfinch.com/signup), go to the "Redirect URIs" section and select `+ Add Redirect URI`. We are going to use [https://example.com](https://example.com) for testing purposes. In production, you will want to use your own application's urls for the Redirect Uris (and remove all mentions of [https://example.com](https://example.com) or [http://localhost](http://localhost)). Redirect URIs are only needed if you are redirecting to Finch Connect. If you decide to use our embedded Finch Connect flow, you do not need to specify a redirect\_uri; the SDK does this for you. We will launch [Finch Connect](/how-finch-works/finch-connect) - our secure authorization flow for your users to grant your application access to their systems - by making an API call to the endpoint below. Make sure to replace `` with the client id found in your [Finch Dashboard](https://dashboard.tryfinch.com/signup). Remove the angle brackets when replacing ``. `customer_id` and `customer_name` can be any identifiers you have internally for your end users. After the API call succeeds, navigate to the URL found in the response body on your browser. ```cs theme={null} curl https://api.tryfinch.com/connect/sessions \ -X POST \ -H "Content-Type: application/json" \ -u ":" \ --data-raw '{ "customer_id": "", "customer_name": "", "products": ["directory", "individual", "employment"], "redirect_uri": "https://example.com", "sandbox": "finch" }' ``` ```cs theme={null} { "session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "connect_url": "https://connect.tryfinch.com/authorize?session=f47ac10b-58cc-4372-a567-0e02b2c3d479" } ``` Note that we have set `sandbox=finch`. This is required only when testing in our [sandbox environment](/implementation-guide/Test/Finch-Sandbox) ## Log in to the Finch sandbox account Select any provider on the selector page and log in with [valid mock credentials](/implementation-guide/Test/Finch-Sandbox#simulating-credential-flows). For example, you can choose ADP Workforce Now and log in with the credentials `good_user` and `good_pass`. ## Exchange the authorization code for an access token After successfully logging in via Finch Connect, your browser will be redirected to `https://example.com` with the query parameter `code` in the browser URL. Copy the `code` from the url and save it in your text editor. In a production system, however, the browser will redirect to your url and your application will automatically copy the `code` and perform the remaining steps programmatically. To exchange the `code` for a token, we use the `curl` command below. Copy the code below, paste into your text editor, replace the `` in the command with the one you saved above (making sure to not include the angle brackets). ```bash theme={null} curl https://api.tryfinch.com/auth/token \ -X POST \ -H "Content-Type: application/json" \ --data-raw '{ "client_id": "", "client_secret": "", "code": "", "redirect_uri": "https://example.com" }' ``` ```json theme={null} { "company_id": "4ab15e51-11ad-49f4-acae-f343b7794375", "account_id": "ac3a2af9-ce03-46c4-9142-81abe789c64d", "connection_id": "bc3a2af9-ce03-46c4-9142-81abe789c64d", "provider_id": "adp_workforce_now", "products": ["directory", "individual", "employment"], "client_type": "production", "connection_type": "provider", "access_token": "7e965183-9332-423c-9259-3edafb332ad2", "customer_id": "7ff74b71-0413-4dbb-a18f-18b1afef4ce6", "token_type": "bearer" } ``` **Congratulations!** You have sent your first request to Finch's API. The next step is to embed [Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) into your application. # Unified API Glossary Source: https://developer.tryfinch.com/how-finch-works/unified-employment-api-glossary Use this glossary to familiarize yourself with terminology used in Finch's documentation and API reference. ### Provider A *provider* is an employer's HRIS, Payroll, or other employment system. The provider is the system of record for the data connected to the Finch APIs. Providers can be referenced within the Finch APIs by their `payroll_provider_id`. ### Employer An *employer* is an organization or company that hires and pays employees. An employer may consist of [one or many entities](/implementation-guide/Backend-Application/Manage-Connections) and use one or many systems of record (i.e. [payroll providers](/integrations/providers)) to manage and pay employees. Employers can be referenced within the Finch APIs by their Finch-issued `connection_id`. ### Entity An *entity* is a grouping of employees within a payroll system. Entities vary by payroll provider and may be configured by the employer. For example, an entity could be defined by: * EIN * Company code * Division * Location * Or any other grouping of employees defined by the payroll system If an employer has multiple entities within their payroll system, they may connect one or more entities to a connection. This would be represented as a single Finch connection with the same `connection_id` and managed using a single access token. ### Individual An *individual* is a unique person with distinctive attributes, represented as *fields*, who is currently or formerly employed at an *employer*. Individuals can be referenced within the Finch APIs by their finch-issued `individual_id`. Contractors are also considered individuals. ### Field A *field* is a specific employment data element or attribute displayed within Finch's standardized data model pulled directly from an employment system. ### Product A *product* is a subgroup of Finch's standardized data model related to a particular segment or workflow of an employment system. Finch currently has four products: [Organization](/products/organization/Overview), [Payroll](/products/payroll/Overview), [Deductions](/products/deductions/Overview), and [Documents](/products/documents/Overview). ### Connection A *connection* is the link created between your application and the employer's provider through Finch. A connection is established after an employer authenticates via [Finch Connect](/how-finch-works/finch-connect). A connection is defined by a unique `connection_id`. An *employer* may have [one or many connections](/implementation-guide/Backend-Application/Manage-Connections) depending on if the employer uses multiple payroll providers. For example, if the employer uses Provider A to manage US-based employees and Provider B to manage international employees, the employer would need to create two Finch connections. ### (Employer) Account An employer *account* is used to connect their company's data to Finch. Employers can connect with various *authentication methods* such as an HR admin's account, an API service account (i.e. API token), or a third-party administrator account. ### Access Token An *access token* represents a single *connection* with an employer entity and allows the developer to query data from the associated employment system of the employer entity. You should treat access tokens with the same [level of security](/implementation-guide/Backend-Application/Store-Tokens) as you would passwords. ### Product scope A *product scope* determines the specific data your *application* can access from the employer's provider. Each product scope refers directly to a Finch API endpoint. If a connection's access token does not have the product included, the request will be blocked with a 401 Unauthorized error. ### Application An *application* is a unique set of `client_id` and `client_secret` credentials that enable you to launch [Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) and [receive access tokens](/implementation-guide/Connect/Retrieve-Access-Token). An application essentially groups your *connections* with your Finch "environment". Finch has three environments: sandbox, testing, and production. The sandbox application connects only mock providers. The testing application connects live providers, but in a limited capacity. The production application connects live providers without any limitations. ### Authentication Method An *authentication method* is the specific technique that an employer account uses to connect their provider. Finch supports OAuth 2.0, API token, user credentials, and assisted as authentication methods to allow you maximum flexibility in offering integrations to your end customer. Each method provides a distinct balance between reliability and data accessibility depending on the needs of your application and your customer. See the "Products" section in the [Provider Field Support](/integrations/providers) for each provider's supported authentication methods. You can also use the `authentication_methods` field on the [Providers](/integrations/providers) endpoint of the API. ### Integration Type An *integration type* refers to one of two ways that Finch organizes our provider integrations. *Automated integrations* are the primary integration type offered by Finch, and offer the highest level of data responsiveness. *Assisted integrations* enable Finch to offer the highest level of provider coverage, while maintaining an API-first experience for developers. See our [Integration Types](/integrations/integration-types) page for more details. ### Automated Integration An *automated integration* syncs data automatically from the employment system once a connection is created. Finch will then proactively sync with the employment system on our periodic [Data Sync](/developer-resources/Data-Syncs) cadence. A full list of Finch's automated integrations can be referenced on the [Providers](/integrations/providers) overview. ### Assisted Integration An *assisted integration* syncs data through a manual service model powered by Finch's Product Operations team. The data is synced on a slower cadence compared to automated integrations. Assisted integrations help expand coverage to the long tail of providers not otherwise covered by automated integrations. Finch is continuously updating assisted integrations to automated integrations based on customer demand and provider availability. A full list of Finch's assisted integrations can be referenced on the [Providers](/integrations/providers) overview. ### Data Sync A *data sync* is the cadence that Finch synchronizes our system with the employer's provider system to ensure consistent, up-to-date data. Finch's API responses will return employer data from the most recent successful data sync to increase performance and reduce latency. ### Job A *job* is a reference object to an API request submitted to Finch which is scheduled to be asynchronously completed. Jobs can be completed automatically (such as data syncs or automated benefit tasks) or asynchronously (such as assisted benefit tasks). A job can be referenced within the Finch APIs by its Finch-issued `job_id`. ### Payment A *payment* is the summary of the monetary transactions an employer provides to employees in return for their work during a specified period of time. Types of payments can include regular payments (salary, wages, etc.) or off-cycle payments (bonuses, commissions, etc.). Payments can be referenced by their Finch-issued `payment_id`. ### Pay Statement A *pay statement* is a detailed breakdown of the *payment* by employee. Pay statements, also known in the industry as "paystub" or "payslip" provide comprehensive information on an individual's gross pay, net pay, earnings, taxes, employee deductions, and employer contributions for a specified pay period. Pay statements can be referenced by their Finch-issued `payment_id`. ### Pay Groups A *pay group* refers to a group of employees within an employer that are paid on the same payroll frequency for on-cycle payments. An employer can have multiple pay groups. Each pay group retrieved by Finch will have a description and the payroll frequency associated with it, as obtained from the payroll system. ### Earning An *earning* refers to the various types of compensation an employee receives in exchange for their services during a specific pay period. Some examples of earnings are salary, wage, bonus, commissions, tips, and allowances. Earnings are the detailed breakdown of an employee's `gross_pay` found on the *pay statement*. ### Tax A *tax* refers to the mandatory financial charges imposed by government entities that are withheld from an employee's earnings based on several factors like earnings amount, the employee's tax bracket, and more. These amounts are deducted from the employee's gross earnings and are remitted directly to the relevant tax authorities by the employer on behalf of the employee. Several types of taxes commonly found on a pay statement include federal income tax, state income tax, and social security tax. ### Benefit A *benefit* is a non-wage form of compensation available to employees often aimed at enhancing the overall well-being, financial security, or work-life balance of the employee. Some benefits can be available company-wide or individual only. ### Deduction An employee *deduction* refers to withholdings that are subtracted from an employee's gross earnings in return for benefits or services rendered by the employer on behalf of the employee. Common employee deductions include health insurance premiums, retirement contributions, voluntary benefits, and any type of custom benefit. ### Contribution An employer *contribution* refers to amounts that the employer pays on behalf of the employee, typically towards benefits or specific programs. Unlike deductions, which are taken from the employee's gross earnings, employer contributions represent additional amounts that the employer is contributing over and above the employee's salary or wages (but not included in the employee's gross earnings). # Batch Requests Source: https://developer.tryfinch.com/implementation-guide/API-Calls/Batch-Requests Batch multiple IDs into a single request to Finch's individual, employment, pay-statement, and deductions endpoints to cut API calls and rate limit risk. ## How batching works Several Finch endpoints — [`/individual`](/api-reference/organization/individual), [`/employment`](/api-reference/organization/employment), and [`/pay-statement`](/api-reference/payroll/pay-statement) — accept multiple IDs in a single request. Finch returns one response with an array of objects, one per ID sent. For example, retrieving individual details for a 1,000-person company by calling `/individual` 1,000 times quickly exhausts your [rate limit](/api-reference/development-guides/Rate-Limits). Since there's no limit on the number of IDs per request, batch all 1,000 `individual_ids` into a single call instead — Finch returns one response with an array of 1,000 individual detail objects. Batching also cuts down the number of round trips your application makes, on top of helping you stay within your rate limit. Each batch endpoint enforces a maximum batch size. Build your application to split `requests[]` into chunks that stay within these limits before sending — a request over the limit fails before Finch processes any item in the batch. | Endpoint | Max batch size | | -------------------------------------------------------- | ---------------------------- | | [`/individual`](/api-reference/organization/individual) | 10,000 items per request | | [`/employment`](/api-reference/organization/employment) | 10,000 items per request | | [`/pay-statement`](/api-reference/payroll/pay-statement) | 10 `payment_id`s per request | For example, to request 25,000 individuals from `/individual`, split the `individual_id`s into three requests of 10,000, 10,000, and 5,000 items rather than sending all 25,000 in one call. ```json theme={null} { "requests": [ { "individual_id": "772b3c4f-d764-433d-bd69-ff8bbac33ffe" }, { "individual_id": "a7a77065-0f68-418d-a85a-da24fb2139b7" }, ... { "individual_id": "84364585-c2ce-40aa-bcc0-666ac9577315" } ] } ``` ### Batching deductions requests Three deductions endpoints also accept multiple individuals in a single call, but with different request shapes than `/individual`, `/employment`, and `/pay-statement`: * [Get Deductions for Individuals](/api-reference/deductions/get-deductions-for-individuals) (`GET /benefits/{benefit_id}/individuals`) — pass a comma-delimited `individual_ids` query parameter instead of a request body. Finch returns an array of `{individual_id, code, body}` objects, one per ID. * [Enroll Individuals in Deductions](/api-reference/deductions/enroll-individuals-in-deductions) (`POST /benefits/{benefit_id}/individuals`) — pass an array of enrollment objects directly as the request body, one per individual. This is an asynchronous batch write: Finch returns a single `job_id` for the whole batch instead of a per-item response. See [Write Data](/implementation-guide/API-Calls/Write-Data) for the enrollment request format and how to verify the job. * [Unenroll Individuals from Deductions](/api-reference/deductions/unenroll-individuals-from-deductions) (`DELETE /benefits/{benefit_id}/individuals`) — pass an `individual_ids` array in the request body. Like enrollment, this is an asynchronous batch write that returns a single `job_id` for the whole batch. ## Batch limit errors A request with more items than an endpoint's max batch size returns a `422` with a `finch_code` of `batch_limit_exceeded`, and Finch does not process any item in the batch: ```json theme={null} { "code": 422, "name": "unprocessable_entity_error", "finch_code": "batch_limit_exceeded", "message": "Batch size exceeds the maximum of 10000 items. Please reduce the number of items in your request." } ``` Split the request into smaller batches — retrying the same request without changing it fails again. See [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors#batch-and-page-size-limit-errors) for the full error format. ## Per-item errors When a batch request is within the size limit, Finch can still return errors for individual items inside it. Finch returns these errors two ways, both in the format described in [Error Types](/api-reference/development-guides/errors/Error-Types): 1. An error per batch request item within the response body. 2. An error at the HTTP status code level. A `200` HTTP status code doesn't mean every item in the batch succeeded — check each item's own `code` in the response body. ```json theme={null} // HTTP 200 status code { "responses": [ { "individual_id": "4f66ec6e-f73c-41e6-bc14-bb2ae53288a0", "code": 404, "body": { "code": 404, "name": "not_found_error", "finch_code": "individual_not_found", "message": "No individual with id 4f66ec6e-f73c-41e6-bc14-bb2ae53288a0 found" } } ] } ``` *** ## Checkpoint + Next Step After completing this step, your application can send thousands of IDs in a single HTTP request and handle each item's result in the response body. Batch errors are one type of error your application can encounter — see [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors) for the others. ## Learn more * [Read Data](/implementation-guide/API-Calls/Read-Data) * [Error Types](/api-reference/development-guides/errors/Error-Types) * [Error Handling](/api-reference/development-guides/errors/Error-Handling) * [Rate Limits](/api-reference/development-guides/Rate-Limits) # Read Organization and Payroll Data Source: https://developer.tryfinch.com/implementation-guide/API-Calls/Read-Data In this guide, you'll learn how to read data from Finch's company, directory, individual, employment, payment, and pay statement API endpoints. You can now make API requests to Finch's various endpoints, such as `/company`, `/directory`, `/individual`, `/employment`, `/payment`, and `/pay-statement`. These endpoints only allow the reading of data from employment providers; they do not permit the writing of data back to the system. Writing deductions and contributions back to the provider is covered in [Write Data](/implementation-guide/API-Calls/Write-Data) step. These calls must be made from your backend using the access token obtained after Finch Connect — see [Backend Security](/implementation-guide/Backend-Application/Backend-Security) for why the access token should never be exposed to your frontend. In this step, you will learn how to make API requests, handle responses, and manage request rate limits. 1. **Choose the appropriate Finch API endpoints**: Pick the endpoint(s) that match the data your application needs. See [Verify Product Scopes](/implementation-guide/Connect/Create-Account#verify-product-scopes) for what each product/endpoint returns, or [How Finch's API is organized](/how-finch-works/data-model) for the full data model. 2. **Batch your requests**: For endpoints that accept multiple IDs — `/individual`, `/employment`, `/pay-statement` — send all the IDs you need in a single call instead of one request per ID. This reduces the number of API calls your application makes and, as a result, helps you stay within your [rate limits](/api-reference/development-guides/Rate-Limits). See [Batch Requests](/implementation-guide/API-Calls/Batch-Requests) for the request and response format. 3. **Set up the HTTP request**: Use an HTTP library such as [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) or [Axios](https://axios-http.com/docs/intro) (or another suitable package) to create an HTTP request. Include the access token in the `Authorization` header using the format `Bearer `. Make sure the HTTP request uses the appropriate method (GET, POST, etc.) and includes any required parameters. ```js theme={null} const url = 'https://api.tryfinch.com/employer/directory?entity_ids[]=64267987-6213-42d1-af2f-d2aa0614e222'; // Replace with the desired endpoint const accessToken = ''; fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` ```python theme={null} import requests def fetch_data_from_endpoint(): url = 'https://api.tryfinch.com/employer/directory?entity_ids[]=64267987-6213-42d1-af2f-d2aa0614e222' access_token = '' headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', } try: response = requests.get(url, headers=headers) response.raise_for_status() data = response.json() print(data) except requests.RequestException as error: print(f'Error: {error}') # Call the function to test # fetch_data_from_endpoint() ``` ```java theme={null} import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class APIClient { private static final String ENDPOINT_URL = "https://api.tryfinch.com/employer/directory?entity_ids[]=64267987-6213-42d1-af2f-d2aa0614e222"; private static final String ACCESS_TOKEN = ""; public static void main(String[] args) { fetchFromEndpoint(); } public static void fetchFromEndpoint() { try { URL url = new URL(ENDPOINT_URL); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN); connection.setRequestProperty("Content-Type", "application/json"); int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // success BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println(response.toString()); } else { System.out.println("GET request failed. Response code: " + responseCode); } } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } } } ``` 4. **Include `entity_ids` query parameter in requests**: When using an access token associated with multiple entities, you must include the `entity_ids` query parameter in all API requests. If you do not provide the `entity_ids` query parameter, Finch will return the following error: ``` { "error": "entity_id_required", "message": "Multi-entity connection requires entity_ids query parameter when multiple entities exist" } ``` Despite the plural name, the API currently accepts exactly one entity ID per request (`entity_ids[]=`) — to fetch data for multiple entities, make one request per entity. 5. **Handle API responses**: When Finch returns a response, parse the JSON data and extract the relevant information needed for your application. All API responses include a header that includes date the data was retrieved. See our Development Guide on [Headers](/api-reference/development-guides/Headers#response-headers) for more details. Store or display the data as needed for your application. ```json Example response theme={null} { "paging": { "count": 15, "offset": 0 }, "individuals": [ { "id": "01220ee6-d32e-4973-8646-c5a197935535", "first_name": "Adrian", "middle_name": "Kylo", "last_name": "Baumbach", "manager": { "id": "c0e619df-77b7-481c-8669-210ba2af97ad" }, "department": { "name": "Quality" }, "is_active": true }, ... { "id": "daac88bc-6ade-459b-9630-68ed7bac5ae9", "first_name": "Glen", "middle_name": "Beckham", "last_name": "Blanda", "manager": { "id": "94917285-773f-4e9f-9018-d919af77c997" }, "department": { "name": "Quality" }, "is_active": true } ] } ``` The `id` values in a response (like the `individual` and `manager` IDs above) stay constant across access tokens generated via the same authentication method. If a connection has multiple access tokens from different authentication methods — for example, one from credentials and another from an API token — those IDs can differ between tokens, since Finch maps its IDs to the underlying employment system's own identifiers, which vary by authentication method. Responses can include `null` field values or, for some requests, a `202` status instead of the shape above. See [Handling API Responses](/api-reference/development-guides/Handling-API-Responses) for why these occur and how to handle each. 6. **Paginate `GET /directory` and `POST /pay-statement` responses**: `GET /directory` and each entry in a `POST /pay-statement` request return paginated results using `limit` and `offset`. Set `limit` explicitly — if you omit it, Finch returns only the default page size, not the full result set. | Endpoint | Default `limit` | Max `limit` | | ---------------------------------------- | --------------- | ----------- | | `GET /directory` | 10,000 | 10,000 | | `POST /pay-statement` (per `payment_id`) | 5,000 | 5,000 | Loop on `offset`, adding the number of items received each time, until the response's `paging.count` shows there are no more records to fetch: ```js theme={null} async function fetchAllDirectory(accessToken) { const individuals = []; const limit = 10000; let offset = 0; while (true) { const url = `https://api.tryfinch.com/employer/directory?limit=${limit}&offset=${offset}`; const response = await fetch(url, { headers: { 'Authorization': `Bearer ${accessToken}` }, }); const data = await response.json(); individuals.push(...data.individuals); if (data.individuals.length < limit) break; offset += limit; } return individuals; } ``` A `limit` above the max returns a `422` with a `finch_code` of `page_size_limit_exceeded`. See [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors#batch-and-page-size-limit-errors) for the error format. 7. **Handle errors and edge cases**: Finch returns `4XX` or `5XX` [error types](/api-reference/development-guides/errors/Error-Types) when a request fails, sometimes due to an unsupported response from the underlying employment system. See [Server errors](/implementation-guide/Backend-Application/Mitigate-Errors#server-errors) in Mitigate Errors for a retry-with-backoff implementation and when to contact support with the `Finch-Request-ID`. 8. **Handle 401 re-authentication errors**: A `401` response with a `finch_code` of `reauthenticate_user` means Finch lost access to the employer's provider and the employer must reauthenticate. See [Reauthentication errors](/implementation-guide/Backend-Application/Mitigate-Errors#reauthentication-errors) in Mitigate Errors for the full flow. 9. **Manage rate limits**: Finch enforces [rate limits](/api-reference/development-guides/Rate-Limits) per product on a rolling 60-second basis, for both applications and access tokens. Batching your requests (see step 2 above) is the main way to stay within these limits. If Finch returns a `429` HTTP status code, back off and retry — see [Rate limit errors](/implementation-guide/Backend-Application/Mitigate-Errors#rate-limit-errors) in Mitigate Errors for the full model and a retry implementation. *** ### Checkpoint + Next Step After completing this step, your application will be able to interact with the Finch API endpoints, read the necessary data, and handle various error scenarios. If all you need is to read data, the next step is to [batch requests](/implementation-guide/API-Calls/Batch-Requests). If you need the ability to write data back to the provider, follow the [Write Data](/implementation-guide/API-Calls/Write-Data) step. Otherwise, you can move on to [Prepare the Employer Experience](/implementation-guide/Integration-Preparation/Manage-Integrations). ## Learn more * [Handling API Responses](/api-reference/development-guides/Handling-API-Responses) * [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors) * [Monitor Usage](/implementation-guide/Backend-Application/Monitor-Usage) # Write Deductions Source: https://developer.tryfinch.com/implementation-guide/API-Calls/Write-Data In this guide, you'll learn how to write deduction and contribution changes to Finch's deductions API endpoints. ## Quick Start Checklist 1. ✓ Identify supported providers 2. ✓ Get, register, or create company-level deduction to receive `benefit_id` and `job_id` 3. ✓ **Wait for company-level deduction job to complete** (poll GET /jobs/manual/ or use webhook) 4. ✓ **Call GET /jobs/manual/ to verify job succeeded** (check response body for errors) 5. ✓ **If job failed, alert personnel and retry with corrections** (do NOT proceed to enrollments) 6. ✓ Enroll individuals using verified `benefit_id` from successful job 7. ✓ **Verify individual enrollment jobs succeeded** (call GET /jobs/manual/ for each enrollment job) As with all Finch API calls, these requests must be made from your backend — see [Backend Security](/implementation-guide/Backend-Application/Backend-Security). Our Deductions product allows developers to write payroll [contributions](/how-finch-works/unified-employment-api-glossary#contribution) and [deductions](/how-finch-works/unified-employment-api-glossary#deduction) changes for retirement, medical, and other benefit use cases. Finch Deductions APIs operate at two levels: the **company-level** and the **individual-level**. **Company-level** APIs allow you to create and update deductions at the company-level. For automated integrations you can also read company-level deductions. **Individual-level** APIs allow you to enroll and un-enroll individuals in deductions, and update their individual-level configurations. For automated integrations you can also read individual-level enrollments. ## Identify Supported Providers Before implementing our Deductions APIs, make sure you identify providers that support the types of deductions and features your use case requires. ### Assisted vs Automated Integrations Deductions Support You can identify which providers are automated and assisted using our [Provider Network](/integrations/providers). #### Automated Integrations * Both **reading** *and* **writing** are supported. * Writing is performed near-real-time in the provider. * Reading provides state of the system when the request is executed. * No configuration period. #### Assisted Integrations * Only **writing** is supported. * See [Integration Types: Assisted](/integrations/integration-types#assisted) for the most up to date SLAs for configuration period and data syncs. ### Use the providers endpoint or field support matrix to identify provider that support your use case The types and features of each deduction can vary between providers. Providers have varying limitations on which operations are available and which actions can be performed. Finch provides two tools to help you identify the types and features of deductions available for a given provider. 1. **Providers Endpoint** - The [providers](/api-reference/management/providers) endpoint provides a list of all providers and the types of deductions they support. 2. **Field Support Matrix** - The [Field Support Matrix](/integrations/field-support) provides a list of all providers and the types of deductions they support, as well as the features available for each deduction type. If you try to make a request using an access token that does not allow a certain configuration or deduction type, our API will respond with a 400 or 422 status code (see [Errors](/api-reference/development-guides/errors/Error-Types)), depending on the error. This endpoint can help you avoid those errors by understanding beforehand what types of requests you can make. ### Prepare for provider limitations when creating company level deductions Some providers do not allow creation of company level deductions using the Finch API ([Create Deduction](/api-reference/deductions/create-deduction)). Use the providers endpoint or field support matrix explained above to identify providers that do not support this for deductions. For those providers, you should confirm with the employer that the correct deduction is set up in their system prior to enrolling individuals through Finch. Then use the Register (assisted integrations) or Get All Deductions (automated integrations) endpoints to get the `deduction_id` for the company level deduction. Then you can enroll and update invidual level deductions. If you try to enroll an employee in a deduction that is not set up, you may receive a `422` response code from Finch indicating that the deduction is not set up by the employer. In these cases, you should reach back out to the employer to ensure the deduction has been correctly set up. ## Verify successful deduction job completion using jobs endpoint For all deduction write requests, both automated and assisted, call either  `GET /jobs/{job_id}` or the [retrieve a manual job endpoint](/api-reference/management/retrieve-a-manual-job) to check the job status and response body which will include a message with details about the cause of any errors. ## Getting and Creating Company Level Deductions Before your application can manage individual enrollments and updates for individuals, your system needs the Finch `benefit_id` for the company wide deduction that the individual is or will be enrolled in. The Finch Deduction API has three endpoints that return a `benefit_id` in the response body. For example, a creation request will respond with: ```json theme={null} { "benefit_id": "e8b90071-0c11-471c-86e8-e303ef2f6782", "job_id": "be1b3351-a88e-46c2-96e4-c2cf38e529a7" } ``` Your application will use this `benefit_id` to perform enrollment, un-enrollment, and deduction retrieval actions on individuals. Your application can use the `job_id` and the [Retrieve a Manual Job](/api-reference/management/retrieve-a-manual-job) endpoint to get the status of the job. The valid job status responses will be either `pending`, `in_progress`, `complete`, or `error` with a response body further explaining the response. **Create Deduction**, **Register Deduction**, and **Get All Deductions** are the endpoints that return a `benefit_id` to use for enrolling and updating individual deductions and contributions. Your application should use the appropriate endpoint based on if the connection is automated or assisted for deductions and if the deduction already exists in the provider system. | Endpoint | Description | Automated/Assited Support | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | ------------------------- | | [Get All Deductions](/api-reference/deductions/get-all-deductions) | Get all existing company-wide deductions and contributions | Automated Only | | [Register Deduction](/api-reference/deductions/register-deduction) | Register one existing company-wide deduction or contribution | Automated and Assisted | | [Create Deduction](/api-reference/deductions/create-deduction) | Create a new company-wide deduction or contribution (not supported for all providers) | Automated and Assisted | **CRITICAL: Always verify job SUCCESS before enrolling individuals** After receiving a `benefit_id` from Create Deduction or Register Deduction, you MUST verify the job completed successfully before making any enrollment requests with that `benefit_id`. **How to verify:** 1. Wait for the job to complete by either: * Polling [GET /jobs/manual/](/api-reference/management/retrieve-a-manual-job) until `status` is `complete`, OR * Listening for the [job completion webhook](/developer-resources/Webhooks#job-completion) 2. Once complete, call [GET /jobs/manual/](/api-reference/management/retrieve-a-manual-job) to check the response `body` for error codes and messages 3. **If the job has an error, alert appropriate personnel and do not proceed with enrollments** **Why this matters:** A job status of `complete` does NOT mean success—it means the job finished processing. The job could complete with an error. If there was an error, the response body will contain details about what went wrong. You must correct the issue and submit a new request—Finch will not automatically retry failed jobs. If you enroll individuals using a `benefit_id` from a failed job, all enrollment requests will fail. Recovering from this scenario requires complex retry logic that most applications are not designed to handle. **Always call the jobs endpoint to verify success after completion.** ## Enrolling and Unenrolling Individuals ### Creating new individual enrollments To enroll a new individual for a contribution or deduction, use the `benefit_id` returned from the appropriate deductions endpoints above, and make a request to [`POST /benefits/{benefit_id}/individuals`](/api-reference/deductions/enroll-individuals-in-deductions) request. This is a batch request endpoint. In the request body, you should provide a list of objects. Each object will specify the `individual_id` (from the directory endpoint in Organization), and a `configuration` object which specifies the enrollment configuration to applies to that individual Use the API Reference to identify which fields should be included in the object for specific types of deductions. Note that none are required by our API, but the provider may require specific fields and return an error if they are not included. ### Updating existing individual enrollments To update the enrollment for currently enrolled individuals, use the same `POST /benefits/{benefit_id}/individuals` endpoint that you use to enroll new individuals. When updating an existing enrollment for an individual, the enrollment configuration will be completely overwritten with the new configuration provided in the request, so please make sure to include the entire desired configuration. Since they both use the same endpoint, these update requests can be submitted in the same batch request as new enrollment requests. ### Un-enrolling individuals You can unenroll individuals by using the [`DELETE /benefits/{benefit_id}/individuals`](/api-reference/deductions/unenroll-individuals-from-deductions) endpoint. This will remove the enrollment configuration for an individual. ### Deduction Sequence Diagram The following diagram shows the basic deductions flow. It can be used with either [Register](/api-reference/deductions/register-deduction) or [Create](/api-reference/deductions/create-deduction) endpoints to obtain the benefit\_id. The flow is very similar for use with the [Get All Deductions](/api-reference/deductions/get-all-deductions) (automated integrations only) except that your application will need to handle a response with multiple benefit objects (see the API reference for response fields and examples). deductions flow.png ## Handling Failures Managing deductions and contributions is a time and money-sensitive activity. Therefore, in the unlikely event that a request through Finch fails, we recommend that your team have a process in place to handle enrollments or to inform employers. We recommend leaving adequate buffer between request submission via Finch and payroll cutoff dates to account for time to address issues. Our recommendation is that you submit a request with enough time to have at least 1 day between the response from Finch and the cutoff date. For an automated connection, that means submitting the request at least 24 hours before the cutoff. For an assisted connection, the recommended time is 3 days to account for the 2 day SLA. Enrollment and un-enrollment requests and responses are batched. This means that some enrollments/un-enrollments could succeed while others fail. For both automated and assisted integrations expect a job\_id in the response body. You can use this job\_id to get the status of the job and see which individuals were successfully enrolled or un-enrolled. ```json title=Top-level status code: 200 theme={null} { "job_id": "497d98f3-580a-4ab9-830a-af2346d029b2", "status": "complete", "body": [ { "individual_id": "430f9d95-1dcf-4b99-b616-45f814416890", "code": 500, "message": "Internal server error" }, { "individual_id": "647975ac-1e0f-4e9c-b705-e3042da48581", "code": 404, "message": "Individual not found" } ] } ``` ## General Deductions Schedule Since enrolling individuals in deductions and contributions can be a sensitive activity, it is helpful to understand some of the nuances around payroll in general. ### How do payroll deductions work? Each payroll contains four important dates to know. 1. **Payroll Start Date** - The first day of the pay period 2. **Payroll End Date** - The last day of the pay period 3. **Payroll Close Date** - The last date to make changes for that pay period 4. **Paycheck Date** - The date on which employees are paid Note - You can get the payroll `start_date`, `end_date`, and the `pay_date` for past pay statements using our pay statement API, but our system cannnot provide the payroll close date. You will need to either get that information from the employer or set expectations for update based on their close date generically ### Timing submissions It is important to submit any employee deductions and contribution changes before the pay close date in order to take affect for the current pay period. If any changes are submitted after the payroll close date, they will only affect the next pay period, not the current. Since each payroll close date is different per provider, it is important to know this date and set proper expectations with your customers. For assisted connections, it is important to submit payroll deductions to our API 3 days before the customer's payroll close date. This will help ensure that changes can be processed within the current payroll period (unless an `effective_date` for a future payroll period is explicitly specified in your API request). Otherwise, the change will be executed on the next payroll period. ### Effective Date The `effective_date` parameter allows you to control when deduction or contribution changes take effect in an employee's payroll. Use this parameter to schedule changes for an employee that will apply in future pay periods. *Effective date is not supported for Justworks or QuickBooks. It is supported for all other providers where Deductions is enabled.* #### How To Use Effective Dates When you submit a deduction or contribution change with an `effective_date`, Finch processes your request within 2 business days of the specified effective date. **Immediate Changes** * Scenario: You need a change to take effect as soon as possible. * How to do it: Don't specify any `effective_date` parameter. * What happens * Finch submits the change to the payroll provider immediately for Automated providers, or within the 2 day SLA for Assisted providers. * The change should be reflected in the current or next pay period, depending on the provider's payroll cutoff date **Example** ```json title=Top-level status code: 200 theme={null} { "amount": 500, "type": "401k" // No effective_date specified } ``` **Scheduled Changes** * Scenario: You want a change to begin on a specific date. * How to do it: Set `effective_date` to a date more than 2 business days in the future. * What happens * Finch schedules the change and submits it to the payroll provider on or up to 1 business day before your specified date. * The change will be included in the pay period containing your effective\_date. If that pay period has already closed by the time Finch submits the change, it will apply to the next available pay period instead. * Your job will show a `pending` status until Finch submits it. **Example** ```json title=Top-level status code: 200 theme={null} { "amount": 300, "type": "401k", "effective_date": "2026-02-15" } ``` **Scheduling Limits** * Effective dates in the past or within the next 2 business days will be processed immediately for Automated providers and within the 2 day SLA for Assisted providers. * There is no hard limit on how far in the future you can schedule changes, but we recommend scheduling changes no more than 90 days in advance. The job will be stay in `pending` for this duration. **Batch Requests with Effective Dates** You can include an effective date when submitting multiple deduction or contribution changes in a single batch request. Note that the entire batch should have the same effective date. When all updates in a batch share the same effective date: * All changes are processed together as a group * They follow the same timing rules as single requests: * Historical dates: Submitted immediately * Future dates: Scheduled and submitted on or shortly before the effective date * No date: Submitted immediately #### Tracking Request Status **Monitoring Scheduled Changes** Use the job status endpoint to check on scheduled changes: ```json title=Top-level status code: 200 theme={null} GET /api/jobs/{job_id} ``` #### Understanding Request States When you submit a change with a future effective date, you can check the status of that change via the manual job status endpoint: 1. `pending`: The change is scheduled but not yet submitted to the provider 2. `in_progress`: Finch is submitting the change to the provider 3. `complete`: The change has been successfully submitted into the payroll system 4. `error`: Something went wrong (see error details for resolution steps) For batch requests, ensure that all individuals in the batch have been processed successfully. Submit another request for any individuals that were not successful. #### Cancel or Modify a Request Requests will remain in `pending` status until submitted to the provider. You can use the update or cancel endpoints to modify scheduled changes as long as the request is still pending. **Example** As an example, if the payroll period is **June 1 - 15**. The payroll close date might be June 16 so payroll can be processed before Tuesday, June 17. Therefore, it would be important to submit payroll deductions via the Finch API by June 11 for those to take effect during the **June 1 - 15** payroll.
  June 2022
  Su Mo Tu We Th Fr Sa
  01 02 03 04 05 06 07
  08 09 10 11 12 13 14
  15 16 17 18 19 20 21
  22 23 24 25 26 27 28
  29 30
Some payroll providers offer a dedicated payroll representative to help with making payroll changes. If a payroll rep is helping your customer's HR admin with changes in their system, it is important that you make it explicitly clear who does what so that the payroll rep does not overwrite any changes Finch has previously made. Calling out Benefit Code types and using thoughtful descriptions (e.g. with your company name) help. **Best Practices** Do: * **Use future effective dates for planned changes** like new hire benefits or scheduled contribution increases * **Omit effective\_date for urgent changes** that should apply as soon as possible * **Allow at least 2 business days lead time** when scheduling future changes * **Monitor job status** for scheduled requests to ensure they're processed on time * **Check provider-specific behavior** if you need precise timing guarantees Don't: * **Rely on retroactive processing** for past effective dates - most providers don't support this * **Specify effective dates within 2 business days** if you need a guaranteed future date (they'll be processed immediately) * **Assume immediate application** even without an effective date - payroll cutoff dates may delay application to the next period * **Create a batch request with different effective dates** ## FAQs **Question** Are all deductions requests processed First In First Out (FIFO)? **Answer** If requests do not include an `effective_date`, the requests are processed in the order they are received. If you submit multiple requests for the same individual the last request processed will overwrite any previous requests. For requests that include an `effective_date`, those enroll requests will be processed on the future `effective_date` rather than the order in which they are received. **Question** What happens if I submit an enroll request for an individual who is already enrolled in a deduction? **Answer** If you submit an enroll request for an individual who is already enrolled in a deduction, the existing enrollment will be updated with the new configuration provided in the request. The status of the request will be a 200 instead of a 201. **Question** How does including an `effective_date` affect when the request is processed? For example, if for the same individual we submit multiple requests with different effective dates, will the requests still be processed in the order they are received or by `effective_date`? **Answer** The `effective_date` parameter determines when the request is processed in the provider system. The request will be processed on the `effective_date`, which must be in the future. Requests should be batched by `effective_date`, and the order of processing will be based on the `effective_date` rather than the order in which they are received. If you submit multiple requests with different `effective_date`s for the same individual, the last request with the latest `effective_date` will overwrite any previous requests. **Question** Is the `effective_date` that is included in the request, the date that is input into the provider's system? **Answer** For *assisted integrations* The `effective_date` that is submitted will be entered into the provider system if the provider has the capabilities to ingest a future effective date and the date is within the allowed range. In case the provider does not have this capability, we will apply the change on the effective date. Note that `effective_date` is not supported across all providers, some do not accept past effective dates, and some have a limited future window for dates. For *automated integrations*, we apply the changes on the effective date and do not enter an effective date into the provider system. You can expect that the enrollment will be effective for the pay period that the request is processed if it is processed before the close date of that pay period. Include an `effective_date` in a future pay period if you want the enrollment to be effective for that pay period. ### Why Job Verification Matters When you create or register a company-level deduction, Finch returns both a `benefit_id` and a `job_id` immediately. However, this does not mean the deduction has been successfully created in the provider system yet. The job may still be processing (`pending` or `in_progress` status), or it could complete with an error. **Understanding Job Status:** A critical distinction exists between job completion and job success: * `status: complete` means the job finished processing—it does NOT guarantee success * You must call [GET /jobs/manual/](/api-reference/management/retrieve-a-manual-job) and inspect the response `body` for error `code` and `message` fields to determine if the job actually succeeded * Common failure scenarios include: provider validation errors, missing required fields, duplicate deductions, or provider system issues **Determining When to Check:** You have two options for knowing when to check the job status: * **Polling:** Repeatedly call GET /jobs/manual/ until `status` changes to `complete`, then examine the response body. This is not recommended. If you opt to use the approach we recommend polling every 1 hour for automated integrations and once per day for assisted integrations. * **Webhooks:** RECOMMENDED Subscribe to the [job completion webhook event job.benefit\_\*.completed](/developer-resources/Webhooks#job-completion) to be notified when the job completes, then call GET /jobs/manual/ to examine the response body **Both approaches require calling the jobs endpoint** to verify success and retrieve error details. The webhook simply eliminates the need to poll repeatedly. **The Problem:** If you use the `benefit_id` to enroll individuals before confirming the company-level deduction job succeeded, you're submitting enrollment requests for a deduction that may not exist or may have failed to create. These enrollment attempts will be queued as jobs, but they will all fail because the underlying `benefit_id` is invalid. **Handling Failures:** If the company-level deduction register or create job completes with an error: 1. Review the `code` and `message` in the response body to understand what went wrong 2. **Alert appropriate personnel** (e.g., log the error, notify your support team, or surface the error to the user) so the issue can be addressed promptly 3. Correct the issue in your request (e.g., fix validation errors, adjust deduction configuration) 4. Submit a new Create Deduction or Register Deduction request 5. **Finch will not automatically retry failed jobs—you must handle retries in your application** **Important:** Do not silently fail. Many developers discover job failures only after attempting enrollments and wondering why nothing worked. Implement proper error handling and alerting when company-level deduction jobs fail. **Why This Is Complex to Fix After the Fact:** Once you've sent 50+ enrollment requests based on a failed `benefit_id`, you must: 1. Detect that the original deduction creation failed (by finally checking the job body) 2. Retry creating the company-level deduction with corrections based on the error message 3. Track which individual enrollments failed 4. Retry all failed enrollments with the new `benefit_id` 5. Handle any individuals whose status may have changed during this process Most applications are not designed to queue and retry batch operations in this way, leading to incomplete enrollments and data inconsistencies. **The Solution:** Always verify job success before proceeding with individual enrollments by calling [GET /jobs/manual/](/api-reference/management/retrieve-a-manual-job) after the job completes. This simple check prevents cascading failures and ensures your enrollments are based on valid deductions. ### Checkpoint + Next Step After completing this step, you will have a good understanding of how to utilize the Finch Deductions API to manage company-level deductions and employee-level enrollments in a robust manner accommodating various provider limitations. Now that you have everything in place for full 360° read/write integrations, you can [Prepare the Employer Experience](/implementation-guide/Integration-Preparation/Manage-Integrations). ## Learn more * [Deductions API](/products/deductions/Overview) * [Supported Providers](/integrations/providers) * [Integration Types: Assisted](/integrations/integration-types#assisted) # Backend Security Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Backend-Security Finch takes security seriously, so we require a backend server to manage all requests and responses to and from Finch APIs. Once the connection has been created via Finch Connect, you can obtain an `access_token` which will be used to call the Finch APIs. We offer several [backend SDKs](/developer-resources/SDKs#backend-sdks) to make the backend integration smoother. We require a backend for several reasons: 1. Since the data from payroll providers is sensitive, making API requests from the backend and storing that data on the backend reduces the likelihood of this data being exposed to malicious persons. 2. Exchanging the authorization `code` for an `access_token` should always take place in your backend to ensure your `client_secret` and `access_token` are never publicly exposed. 3. Likewise, your backend should always [store the access token](/implementation-guide/Backend-Application/Store-Tokens) in a secure database and should never return the access token to the frontend application. # Control Access (Optional) Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Control-Access Learn how to control data access within multi-tenancy applications through role-based access control (RBAC) or other authorization methods. If you have [set up a connection properly](/implementation-guide/Backend-Application/Manage-Connections) and [retrieved data from Finch APIs](/implementation-guide/API-Calls/Read-Data), you may also want to confirm that you are only displaying or processing data relevant to the authenticated user. While this is optional, it's recommended to avoid mixing up data from different customers or employers. For instance, only fetching specific customer data using *their* access token, then only displaying *their* data on *their* account dashboard. If your application is deployed individually per customer (often called **single-tenancy**), there is natural isolation of employer data since each tenant is on a separate instance running on its own set of servers, databases, and other infrastructure. However, if your application serves multiple customers in a single instance (often called **multi-tenancy**), each employer's data should remain isolated from other employers either through authorization, database partitioning, separate schemas, or other techniques. ## Application authorization In order to control user's access to the right data, you can apply **role-based access control (RBAC)** or another authorization permission systems in your application. We will specifically focus on multi-employer RBAC authorization. Multi-employer RBAC involves 4 core elements: * **Users**: A user is an individual who is trying to access their employment data which they granted you access to via Finch Connect. A `user` is assigned `roles`, which in turn grant them the `permissions` they need to access resources. In a multi-employer RBAC, users typically belong to a particular `employer` and their permissions and roles are scoped to that employer. A user in one employer should not, by default, have any permissions or roles in another employer unless explicitly granted. * **Roles** - A role is a collection of permissions that define the actions a user can perform in your application. A role is assigned to a user, and a user can have multiple roles. In a multi-employer environment, roles are typically scoped to a particular employer so that an "Admin" role in Employer A might have different permissions than an "Admin" role in Employer B. * **Permissions** - A permission is a right to perform a specific action or access a specific resource in your application. Permissions are assigned to roles. In a multi-employer context, permissions should be defined in a way that they are also scoped to specific employers. This ensures that granting a permission in one employer doesn't inadvertently grant access to resources in another employer. * **Employers**: An employer is the foundational element of multi-employer scenarios. Each employer represents an isolated unit or environment in your application, like a separate company or organization. Your application must be able to separate and manage data, configurations, and roles for each employer independently, ensuring there's no overlap or unintended sharing. The RBAC system follows a simple logic: A user requests access to a resource, and the system checks if the user has the necessary permissions to access that resource based on the roles assigned to them. > ### Cross-Employer Authorization > > There may be scenarios where a user needs access across multiple employers (maybe they manage multiple employers for a PEO, or Professional Employer Organization. In such cases, your RBAC authorization system must support cross-employer roles and permissions without compromising the security or isolation of individual employers. Building upon the database tables `customers` & `finch_connections` defined in the [Manage Connections](/implementation-guide/Backend-Application/Manage-Connections) guide, in order to implement multi-employer RBAC, we need a few additional tables. * `customers`: Represents the "entities" who use your system. * `finch_connections`: Represents the different connections (i.e. employers) a customer might have in your system. * `users`: Represents individual users within a particular employer. Each user is associated with a specific connection, which defines the context of their roles and permissions. * `roles`: Represents different roles that can be assigned to users within an employer. Each role is associated with a particular connection, signifying the context in which the role exists. * `permissions`: Represents the different actions or operations that can be performed within your system. Permissions are not directly linked to a connection as permissions are typically more generic and can be used across multiple connections. * `role_permissions`: A junction (or associative) table that establishes a many-to-many relationship between roles and permissions. Allows you to assign multiple permissions to a single role and vice versa. * `user_roles`: Another junction table, but this one links users and roles. It determines which roles are assigned to a user in the context of a connection. Each combination signifies the roles a user has within a particular connection, which in turn dictates what actions they can perform with their employment data. Once the database is set up, to implement data access controls, you can use a combination of JOIN statements in your SQL queries to enforce access restrictions based on the user's role or permissions. At a minimum, your application should have an `Admin` role since it is the employer's HR & Payroll admin who should only have the permissions to go through Finch Connect and establish a connection with their employment system. Since a regular employee does not have the permissions to see the whole company-wide details or payroll, they should not be shown the option to connect via Finch. ## Reminder SQL queries via JOIN statements are only one way of implementing multi-employer role-based access control. There are many ways to implement access control that allow more fine-grained authorization or robust permissioning. Choose the best option for your application's needs. Wether you choose to maintain separate environments for each employer or a shared instance with secure access control, being able to minimize the risk of unauthorized data access or mixing up data from different customers or employers is highly valuable. *** ## Checkpoint + Next Step After completing this step, you should be familiar with the database techniques necessary to effectively track the relationship between user accounts and access tokens and implement data access controls based on user roles or permissions. You are now ready to [Manage Connections](/implementation-guide/Backend-Application/Manage-Connections). ## Learn more * [Manage Connections](/implementation-guide/Backend-Application/Manage-Connections) * [Reconcile Employees](/developer-resources/Reconcile-Employees) # Disconnect Connections Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Disconnect-Connections Learn how to disconnect an entire connection or remove specific entities from a connection. A connection exists once an access token is obtained and [stored securely](/implementation-guide/Backend-Application/Store-Tokens). A connection may include one or more entities — for example, separate legal entities or divisions managed by the same employer within the same payroll system. (For more on how connections and entities relate, see [Manage Connections](https://developer.tryfinch.com/implementation-guide/Backend-Application/Manage-Connections). Like all Finch API calls, disconnecting a connection must be done from your backend — see [Backend Security](/implementation-guide/Backend-Application/Backend-Security) for why the access token this requires should never reach the frontend. Finch provides two endpoints depending on whether you need to disconnect an entire connection or just certain entities within it. ## Disconnect an Entire Connection Calling the [`/disconnect`](https://developer.tryfinch.com/api-reference/management/disconnect) endpoint will disconnect all entities associated with the connection tied to the provided access token. Once disconnected, the connection is permanently terminated and the access token is revoked. Use this when you intend to stop syncing data for an employer entirely. ## Disconnect Specific Entities If a connection includes multiple entities, you can remove specific entities without affecting the rest of the connection by calling [`/disconnect-entity`](https://developer.tryfinch.com/api-reference/management/disconnect-entity) with the `entity_ids` you want to remove in the request body. All other entities remain active and the access token stays valid. Use this when an employer connected an entity by mistake, or when your application needs to stop syncing a particular entity while continuing to operate normally for others under the same connection. An `account.updated` webhook will fire for each disconnected entity. If you disconnect multiple entities in one call, you'll receive a separate webhook per entity. ## Choosing Between /disconnect and /disconnect-entity | | `/disconnect` | `/disconnect-entity` | | ------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | **Scope** | Disconnects the entire connection and all entities | Disconnects only the specified entities; others remain active | | **Required input** | Access token only | Access token + `entity_ids` | | **Reversibility** | If you disconnect an entity you did not intend to, a new connect session must be created | If you disconnect an entity you did not intend to, a re-auth session can be used to add the entity(s) back to the connection | | **Employer impact** | The employer will then need to establish a new connection and select the desired entities in Finch Connect | Employer re-authenticates to add the entity back to the existing connection in Finch Connect | If your intent is to disconnect every entity under a connection, use /disconnect directly rather than calling /disconnect-entity for each one. ## Best Practices ### Before You Disconnect **Choose the right endpoint.** Use `/disconnect` to fully offboard an employer. Use `/disconnect-entity` to remove specific entities from a multi-entity connection while preserving the rest. **Disconnect before deleting tokens.** `/disconnect` requires the access token. Always call it before you discard the token from your system. ### Understanding Disconnect Behavior **Billing.** Billing is based on unique `connection_id`s — simply ceasing API calls does not stop billing. Only `/disconnect` removes a connection from billing. (`/disconnect-entity` does not, unless you remove every entity, but `/disconnect` is simpler if that's your intent.) **No reconnect endpoint.** Once a connection is fully disconnected via `/disconnect`, it cannot be reactivated. The employer must go through Finch Connect again, creating a new `connection_id` and a new billable connection. **Only disconnect when you mean it.** A connection in `reauth` status is not a disconnect — prompt the employer to reauthenticate instead. Only call `/disconnect` or `/disconnect-entity` when you're confident you no longer need the data. If you do disconnect an entity by mistake, the employer can re-add it via a reauth session. (Note: reauth lets employers *add* entities but not *remove* them — removal requires `/disconnect-entity`.) **Update your database after a successful `/disconnect-entity` call.** When you receive a `200` response from `/disconnect-entity`, remove the corresponding `entity_id`(s) from your database. If you retain disconnected `entity_id`(s) and continue making data requests with them, those requests will fail with an invalid `entity_id` error. **Updated entity arrays in API responses.** After disconnecting one or more entities, any subsequent call to `/auth-token` performed during re-authentication will only return the entities that are still actively connected. Disconnected entities will no longer appear in the response. If you need the historical context of every entity that was every linked to a connection, use the `/introspect` endpoint. This will return both actively connected and disconnected entities. **Viewing disconnected entities via `/introspect`.** You can always use the `introspect` endpoint to see a full history of entities that have ever been associated with a connection -- including those that have since been disconnected. Each entity in the `entities` object will include an individual `status` field indicating its current status. *** ## Checkpoint + Next Step After completing this step, you should understand when to use `/disconnect` vs. `/disconnect-entity` and what happens to connections and entities in each case. Your application should give customers the ability to disconnect their connection (or specific entities), calling the appropriate Finch endpoint from your backend. Next, learn how to [control user access](/implementation-guide/Backend-Application/Control-Access). If you plan on presenting the data back to the employer via a User Interface, it is crucial to control user access properly to ensure employment data is only viewable by the correct customer account. ## Learn more * [Disconnect Endpoint](/api-reference/management/disconnect) * [Disconnect Entity Endpoint](/api-reference/management/disconnect-entity) * [Manage Connections](/implementation-guide/Backend-Application/Manage-Connections) * [Control Access (Optional)](/implementation-guide/Backend-Application/Control-Access) # Manage Connections Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Manage-Connections In this guide, you’ll learn how to define and manage multi-account, multi-provider, and multi-entity connections based on your customers’ needs. Every [access token obtained](/implementation-guide/Connect/Retrieve-Access-Token) is associated with a connection. Therefore, to prevent mixing up data across different users or employers, it is important to make sure you associate each access token with the correct connections in your application. Implementing a system to track the relationship between your customers and their corresponding access tokens is recommended. Like all Finch API calls, this happens from your backend — see [Backend Security](/implementation-guide/Backend-Application/Backend-Security) for why access tokens should never reach the frontend. ## Define connections Finch defines a connection using a `connection_id`. A connection exists once an access token is obtained. There are a couple scenarios to keep in mind when thinking about connections: 1. **Multi-Provider**
Employers may be using multiple payroll systems to manage employees within their company. For example, an employer may use Payroll Provider A to manage foreign contractors, and Payroll Provider B to manage US-based employees. The employer can only connect one provider in one Finch Connect session; a connection is created for each connected provider. Even though the employer is connecting the same company, Finch will create multiple connections because the underlying `provider_id` is different for each connection. 2. **Multi-Entity**
An employer’s payroll system may consist of one or many entities. An entity is a grouping of employees within a payroll system (e.g.: divisions, EINs). Employers have the ability to select one or multiple entities to connect at once. If an employer selects multiple entities, Finch will create a single connection with one `connection_id` and access token. ## Isolate connections Given these scenarios, your application must be able to manage multiple connections per customer and keep each connection and its corresponding access tokens isolated from the rest. You should store access tokens in your system using the `connection_id`. * `provider_id` = the payroll provider associated with the access token. * `customer_id` = a unique identifier that you create to manage your customers internally > You define the `customer_id`; Finch defines the `connection_id` (more on this below). ### Introspect endpoint The best way to retrieve the unique ids associated with an access token is by calling the [Introspect](/api-reference/management/introspect) endpoint. It will return a JSON body containing account information associated with the `access_token`. ```json Example /introspect response theme={null} { "account_id": "d8ef1814-5913-492f-b5c0-a16e2d6432c9", "client_id": "25ea8bd8-f76b-41f9-96e3-1e6162021c50", "connection_id": "6dab009c-77c8-43d9-8f81-e093f7c65bc1", "company_id": "87eb4bc3-f76b-35e7-78d2-8f7822021d73", "payroll_provider_id": "gusto", "products": [...], ... } ``` ### Example A simple example is a `1:1` connection association. It can be represented by a single database table with columns for `customer_id` and the associated `access_token`. You can use a unique constraint on the `customer_id` column to ensure that each user can have only one associated `access_token`. 1-To-1 Database Schema However, in production, you will want to handle the more [complex connection scenarios](#define-connections) above which have a `1:Many` relationship. This can be represented by two database tables: the *Customers* table one stores the `customer_id` and the *Connections* table stores the `connection_id` which references back to a `customer_id`. 1-To-Many Database Schema In this realistic example: * `connection_id` represents the unique finch variables that define a connection. * A “composite unique constraint” can be set on `connection_id`  values which means that while each of these connections can contain the same values individually, the combination of these values must be unique (hence a unique connection). Now, when you insert data into the *Connections* table, you'll need to ensure that the `connection_id` is unique for each row, while the `access_token` inherently remains unique for each row as well. The `connection_id` (when combined with data from the Finch [/company](/api-reference/organization/company) endpoint) is going to be able to tell you which employers are attached to each customer. ## Enabling multiple connections with Finch Connect To have your customer create multiple connections in your application, your "onboarding" flow or "connections" page must allow them to go through [Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) multiple times. Below is an example User Interface. You can present your customers with a page showing all of their current connections and provide the option to connect more accounts, providers, or company entities. ## Edge cases ### Reauthentication In [reauthentication](/developer-resources/Reauthentication) situations, your customer should be prompted to reconnect their provider again before continuing to use the application. When the Finch Connect flow is completed, a new access token will be generated. Simply replace the old token with the new token and start making Finch API requests with the updated token like before. ### Repeating employees In the [multi-provider or multi-company](#define-connections) scenarios, if your application is combining data across multiple access tokens, you may need to [reconcile employees](/developer-resources/Reconcile-Employees) between responses in order to merge employee data properly. *** ## Checkpoint + Next Step After completing this step, you should know how to associate access tokens with multiple accounts for each new connection. With proper connection organization, you are ready to use the access token to [make API requests](/implementation-guide/API-Calls/Read-Data) to Finch's various endpoints. ## Learn more * [Control User Access](/implementation-guide/Backend-Application/Control-Access) * [Set Up Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) * [Reauthenticating Connections](/developer-resources/Reauthentication) * [Reconcile Employees](/developer-resources/Reconcile-Employees) * [Integration Types: Automated](/integrations/integration-types#automated) # Mitigate Errors Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Mitigate-Errors Identify and handle Finch API responses and errors — null values, 202 responses, server errors, reauthentication errors, and rate limit errors — with mitigation steps for each. This guide covers the responses and errors developers most frequently encounter with the Finch API. Null values and 202 responses are expected parts of a normal response — but your application can misbehave if it doesn't handle them. Server errors, reauthentication errors, and rate limit errors are true error conditions Finch returns when something goes wrong. Your application should expect and handle the [error types](/api-reference/development-guides/errors/Error-Types) documented in the API reference. ## Null values A `null` value isn't an error — it's an expected response value. See [Null Values](/api-reference/development-guides/Handling-API-Responses#null-values) for why Finch returns `null` and how to check for it. ## 202 responses A `202` response isn't an error either — it means the connection exists but data isn't available yet. See [202 Response Codes](/api-reference/development-guides/Handling-API-Responses#202-response-codes) for the retry and backoff behavior your application should implement, or [Testing assisted integrations](/implementation-guide/Test/Finch-Sandbox#testing-assisted-integrations) to reproduce a `202` response in the Finch Sandbox. ## Server errors Server errors (`HTTP 500`) are uncommon but possible. A few error-handling mechanisms help you maintain a good user experience while diagnosing the issue: * **Friendly error page.** Display a user-friendly message instead of the raw server error to maintain user trust. * **Log the error.** Capture the error message, stack trace, request details, and other relevant context. Always log the `finch-request-id` from the HTTP response headers — Finch needs it to diagnose the issue on our side. * **Health checks.** Call the [/introspect](/api-reference/management/introspect) endpoint on a regular basis to monitor the status of your Finch integration and its connections — this helps you identify the source of `500` errors faster. * **Retry.** Retry the request after a delay, or adjust the request parameters — this resolves many transient server errors. **Product outages.** Finch reports all API outages and provider integration incidents at [status.tryfinch.com](https://status.tryfinch.com) — subscribe there for email notifications when Finch creates, updates, or resolves an incident. If a server error persists, contact [Finch Support](/implementation-guide/Deploy-and-Manage/Support) and attach the `finch-request-id` from the response headers. ### Retry example Finch may also return `4XX` or `5XX` [error types](/api-reference/development-guides/errors/Error-Types) due to unsupported responses from the underlying employment system. Retrying immediately may not resolve the issue — the following example retries a failed request with a fixed delay: ```jsx Error handling example theme={null} function fetchDataWithRetry(url, options, retries = 3, delay = 2000) { return fetch(url, options) .then(response => { if (response.status === 500 && retries > 0) { return new Promise(resolve => setTimeout(resolve, delay)) .then(() => fetchDataWithRetry(url, options, retries - 1, delay)); } else { return response; } }) .catch(error => console.error('Error:', error)); } fetchDataWithRetry(url, { method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => console.log(data)); ``` ## Reauthentication errors A reauthentication error means the credentials Finch uses to access an employer's provider system no longer work, and the employer must reauthenticate. This returns an HTTP status code of `401 Unauthorized` with a `finch_code` of `reauthenticate_user` (see [Finch API errors](/api-reference/development-guides/errors/Error-Types)). To handle this error: 1. Catch `401` responses with a `finch_code` of `reauthenticate_user` in your Finch API error handling. 2. Create a new Finch Connect session for the connection using the [`/connect/sessions/reauthenticate`](/api-reference/connect/reauthenticate-session) endpoint, passing the connection's `connection_id`. If your application doesn't already store the `connection_id`, retrieve it by calling [/introspect](/api-reference/management/introspect) with the connection's `access_token`. 3. Direct the employer to complete Finch Connect through your existing flow — for example, prompt them to log in to your application dashboard, or send them a link to reauthenticate. 4. Exchange the resulting authorization code for a new access token — this is the same [access token exchange](/implementation-guide/Connect/Retrieve-Access-Token) used during initial setup. See [Reauthentication](/developer-resources/Reauthentication) for what causes this error and how to handle multi-entity connections, employee permissions, and product scopes when reauthenticating. ## Batch and page size limit errors Finch enforces a maximum batch size on `POST /individual`, `POST /employment`, and `POST /pay-statement`, and a maximum page size on `GET /directory` and `POST /pay-statement`. See [Batch Requests](/implementation-guide/API-Calls/Batch-Requests) for batch size limits and [Read Data](/implementation-guide/API-Calls/Read-Data) for page size limits and the pagination pattern. ### Batch limit errors A request with more items than an endpoint's max batch size returns a `422` with a `finch_code` of `batch_limit_exceeded`: ```json theme={null} { "code": 422, "name": "unprocessable_entity_error", "finch_code": "batch_limit_exceeded", "message": "Batch size exceeds the maximum of 10000 items. Please reduce the number of items in your request." } ``` Split the request into smaller batches. Retrying the same request without changing it fails again — this isn't a rate limit, so a backoff-and-retry strategy won't resolve it. ### Page size limit errors A `limit` above an endpoint's max page size returns a `422` with a `finch_code` of `page_size_limit_exceeded`: ```json theme={null} { "code": 422, "name": "unprocessable_entity_error", "finch_code": "page_size_limit_exceeded", "message": "Page size exceeds the maximum of 10000 items. Please reduce the limit parameter." } ``` Lower `limit` to the endpoint's max and paginate with `offset` to retrieve the remaining records. If your application omits `limit` entirely, `GET /directory` and `POST /pay-statement` return a default page size rather than every record, and no error is returned. Set `limit` explicitly and paginate with `offset` — see [Read Data](/implementation-guide/API-Calls/Read-Data) — otherwise your application will silently process incomplete data. ## Rate limit errors Finch returns a rate limit error with the HTTP status code `429 Too Many Requests` when an application or IP address exceeds its request limit. Review the API [rate limits](/api-reference/development-guides/Rate-Limits) before continuing. Finch's [rate limits](/api-reference/development-guides/Rate-Limits) work on a per-endpoint basis for applications. Finch calls each distinct endpoint a unique product, and sums rate limits on a rolling 60-second basis per product — commonly called a sliding or rolling window rate limit. Think of each product's rate limit as a bucket. Every request to a product (which maps to an API endpoint) adds a gallon of water to that endpoint's bucket and starts a 60-second time-to-live (TTL) timer. When the bucket empties after 60 seconds, the next request restarts the TTL. Stay within these [rate limits](/api-reference/development-guides/Rate-Limits) to avoid request failures. If you hit a rate limit error, implement a [back-off and retry strategy](#rate-limit-example): wait 60 seconds for the bucket to reset, then retry, increasing the wait time exponentially on repeated failures. ### Batch requests [Batch requests](/implementation-guide/API-Calls/Batch-Requests) instead of calling an endpoint once per ID, to reduce your request count and avoid exhausting your rate limit. ### Rate Limit Scenario This scenario shows how an application encounters application-level [rate limits](/api-reference/development-guides/Rate-Limits). Assume your application has five access tokens (Token A–E) making requests to the `company`, `directory`, `individual`, `employment`, `payment`, and `pay-statement` endpoints. Each request to an endpoint adds a gallon of water to that product's application-level bucket. The bucket counts requests across all of the application's access tokens (Token A–E). Organization endpoints have a [capacity](/api-reference/development-guides/Rate-Limits) of 20 max requests per minute. Pay endpoints have a [capacity](/api-reference/development-guides/Rate-Limits) of 12 max requests per minute. Each step below happens within the same 60-second (1-minute) time window. 1. Token A makes 5 requests to [/company](/api-reference/organization/company), 4 to [/directory](/api-reference/organization/directory), and 3 to [/payment](/api-reference/payroll/payment) within a minute. Each bucket is below its capacity, so all of Token A's requests succeed. * Application-level rate limits | Bucket | Capacity | | --------------- | -------------- | | `company` | 5/20 - success | | `directory` | 4/20 - success | | `individual` | 0/20 | | `employment` | 0/20 | | `payment` | 3/12 - success | | `pay-statement` | 0/12 | 2. Token B makes 5 more requests to [/company](/api-reference/organization/company), 4 to [/directory](/api-reference/organization/directory), and 3 to [/payment](/api-reference/payroll/payment) within the same minute. Each bucket is still below capacity, so all of Token B's requests succeed. * Application-level rate limits | Bucket | Capacity | | --------------- | --------------- | | `company` | 10/20 - success | | `directory` | 8/20 - success | | `individual` | 0/20 | | `employment` | 0/20 | | `payment` | 6/12 - success | | `pay-statement` | 0/12 | 3. Tokens C and D each repeat the same pattern — 5 requests to [/company](/api-reference/organization/company), 4 to [/directory](/api-reference/organization/directory), and 3 to [/payment](/api-reference/payroll/payment) — within the same minute. The `company` and `payment` buckets reach full capacity, but Token C's and D's requests still succeed because the limits haven't been exceeded yet. * Application-level rate limits | Bucket | Capacity | | --------------- | ---------------------- | | `company` | 20/20 (FULL) - success | | `directory` | 16/20 - success | | `individual` | 0/20 | | `employment` | 0/20 | | `payment` | 12/12 (FULL) - success | | `pay-statement` | 0/12 | 4. Token E then makes 1 request to [/company](/api-reference/organization/company) and 1 to [/directory](/api-reference/organization/directory). The `company` and `payment` buckets are now full, so any further request to those endpoints — including Token E's `/company` request — returns a 429 rate limit error until the 60-second TTL resets. Token E's `/directory` request succeeds because that bucket isn't full yet. Only successful requests count toward the application-level limit. * Application-level rate limits | Bucket | Capacity | | --------------- | -------------------- | | `company` | 20/20 (FULL) - error | | `directory` | 16/20 - success | | `individual` | 0/20 | | `employment` | 0/20 | | `payment` | 12/12 (FULL) - error | | `pay-statement` | 0/12 | Every fifth request to [/company](/api-reference/organization/company) for each token fails with a 429 rate limit error once its bucket is full. ### Rate limit example The following `RateLimiter` class enforces this quota at the application level. Initialized with a limit (for example, 20 requests per minute for [/directory](/api-reference/organization/directory)), it makes requests up to that limit and pauses further requests until the bucket resets after 60 seconds. Call its `request` method to make API requests through the rate limiter, and initialize a separate `RateLimiter` instance for each endpoint you call. ```js theme={null} class RateLimiter { constructor(limit) { this.limit = limit; this.requests = []; } async request(fn) { const now = Date.now(); this.requests = this.requests.filter((timestamp) => now - timestamp < 60000); if (this.requests.length >= this.limit) { const delay = this.requests[0] + 60000 - now; await new Promise((resolve) => setTimeout(resolve, delay)); this.requests.shift(); } this.requests.push(now); return fn(); } } const directoryRateLimiter = new RateLimiter(20); // 20 requests per minute const url = 'https://api.tryfinch.com/employer/directory'; // Replace with the desired endpoint const accessToken = ''; const fetchIndividualData = ( ) => fetch(url, { method: 'GET', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, }); // Use the rate limiter to make API requests directoryRateLimiter .request(fetchIndividualData) .then((response) => response.json()) .then((data) => console.log(data)) .catch((error) => console.error('Error:', error)); ``` ## Checkpoint + Next Step Your application can now handle Finch's most common error scenarios, making your integration more resilient. Monitoring API requests makes error mitigation easier — see [Monitor API Usage](/implementation-guide/Backend-Application/Monitor-Usage) next. ## Learn more * [Handling API Responses](/api-reference/development-guides/Handling-API-Responses) * [Set Up Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) * [Batch Requests](/implementation-guide/API-Calls/Batch-Requests) * [Rate Limits](/api-reference/development-guides/Rate-Limits) * [Error Types](/api-reference/development-guides/errors/Error-Types) # Monitor Usage Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Monitor-Usage In this guide, you'll find best practices for monitoring your application's usage of Finch to identify patterns and potential issues. Implementing monitoring tools or processes to keep track of your application's usage of the Finch APIs will help you identify patterns and potential issues (see [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors) for more details). Events such as frequent rate limit overages or a sudden increases in error rates can be quickly identified and actioned if proper monitoring is in place. ## Use the Introspect Endpoint The [`/introspect`](/api-reference/management/introspect) endpoint is an extremely important tool when using Finch, allowing you to read account information associated with an access\_token such as the connection status. ## Log finch request id It is best practice to log the `finch-request-id` for every response, whether successful or unsuccessful. The `finch-request-id` can be found in every HTTP response Header. The `finch-request-id` is required by the Finch Support team for debugging request issues. ## Store the connection id Each Finch `access_token` is associated with a static Finch `connection_id`. You can find the id using the [`/introspect`](/api-reference/management/introspect) endpoint. Save this in your data store alongside the access token and use it when contacting Finch Support about an issue. ## Monitor API requests Track API response times to and from Finch. A spike in latency can indicate network problems or possible Finch performance degradations. Continuously check for increases in error rate responses from Finch. This can indicate problems with the Finch APIs or issues with how your application sends requests to the Finch APIs. Track `422` responses by `finch_code` separately from other error rates. A rise in `batch_limit_exceeded` or `page_size_limit_exceeded` means your application is sending requests that exceed [batch or page size limits](/implementation-guide/Backend-Application/Mitigate-Errors#batch-and-page-size-limit-errors) — this won't resolve on retry and needs a code change, not a backoff strategy. Finch reports all API outages and provider integration incidents. You can subscribe to receive email notifications from [https://status.tryfinch.com](https://status.tryfinch.com) whenever we create, update, or resolve an incident. ## Optimize API usage Regularly review your application's usage of Finch APIs and identify opportunities to optimize and improve performance. This may include refining batch request sizes to improve latency, improving error handling, or adjusting request patterns to avoid rate limits. *** ## Checkpoint + Next Step After completing this step, you should be equipped to preemptively identify and address potential issues in your application and your Finch integration, helping you get the most value from Finch's services. Now that you have an application that is connected, secure, please review the [Control Access](/implementation-guide/Backend-Application/Control-Access) and [Manage Connections](/implementation-guide/Backend-Application/Manage-Connections) guides to make sure your application is set up to handle your specific use case. ## Learn more * [Finch Status Updates](https://status.tryfinch.com) # Store Tokens Source: https://developer.tryfinch.com/implementation-guide/Backend-Application/Store-Tokens ***Finch requires developers to store tokens on the backend server for improved security controls***. To reduce the likelihood of unitentional exposure of employer access tokens or other private information, you'll need to ensure all access tokens are stored securely. Finch access tokens are "keys" to sensitive information. You should treat access tokens with the same level of security as you would passwords. ## Secure storage best practices Storing tokens securely should be done on the backend (server-side) of your application, not on the frontend (client-side). A frontend application is more susceptible to potential security threats such as Cross-Site Scripting (XSS) attacks or unauthorized access if the client is compromised. No application is 100% secure, but there are ways to reduce the potential of an exposure (and its impact) by following a few best practices: 1. Store tokens on the backend of your application. 2. Encrypt the access token before storing it. 3. Use environment variables or a secure configuration management system to store static sensitive information that needs to be referenced like `client_secret`. 4. Never store access tokens in code files or easily accessible directories with human access. 5. Ensure that tokens are not exposed in URLs, logs, or error messages. 6. Keep all server-side components, libraries, and frameworks up-to-date with security patches to mitigate potential vulnerabilities. Determine the best method for securely storing access tokens in your application's backend. Reference the sections below if you need additional help. ## Encryption To add an extra layer of security, you can encrypt the access token before storing it. Select a strong symmetric encryption algorithm, such as AES-256. Avoid using weak algorithms like DES, as they are susceptible to brute-force attacks due to its small key size (56 bits). ## Never expose access tokens Ensure that tokens are not exposed in URLs, log files, or error messages. Regularly review logs for any exposure. Ensure your frontend application never receives the access token to avoid incidental exposure. Your frontend, client-side application should only receive employment data, never the token itself. ## Stay compliant with data privacy regulations Familiarize yourself with any applicable data privacy regulations, such as GDPR, CCPA, or other regional laws. Implement necessary measures to stay compliant with these regulations when handling, storing, and processing data obtained from the Finch APIs. This includes obtaining user consent when necessary (handled by [Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect)), [managing data deletion requests](/implementation-guide/Backend-Application/Disconnect-Connections), and providing users with the ability to [control their data](/implementation-guide/Backend-Application/Control-Access). *** ## Checkpoint + Next Step After completing this step, you should know how to store access tokens on the backend server, reduce the impact of their exposure, and comply with any data privacy regulations. When a connection is no longer needed, it is best practice to [disconnect the token](/implementation-guide/Backend-Application/Disconnect-Connections) from Finch then delete it from your system. ## Learn more * [Disconnect Tokens](/implementation-guide/Backend-Application/Disconnect-Connections) * [Control Access](/implementation-guide/Backend-Application/Control-Access) # Create a Finch Developer Account Source: https://developer.tryfinch.com/implementation-guide/Connect/Create-Account Create your Finch Developer Account, recieve your application credentials, and pilot how Finch works in our sandbox environment. To get started using the Finch APIs, sign up for a free sandbox account to receive application credentials (a `client_id` and `client_secret`) and pilot how Finch works in a safe testing environment with mock data. Sign Up 1. Go to the [Finch Developer Dashboard](https://dashboard.tryfinch.com/) and sign up for a new account. You'll need to provide your name, company name, email address, and create a password. 2. Once you have created an account and logged in, locate the sandbox application in the upper left which was automatically created. 3. Upon creating the application, you'll be provided with a `client_id` and `client_secret`. You will use these credentials to authenticate your application to obtain access tokens in order to call the Finch APIs. 4. Set up a secure method for storing your `client_id`, `client_secret`, and future `access_token`s to prevent unauthorized access. Here are some methods to securely store these credentials: * **Environment Variables**: Store your `client_id` and `client_secret` as environment variables within your application. When your application needs to use these credentials, it can access them from the environment variables without exposing them in your source code. * **Secure Database**: [Store the access tokens](/implementation-guide/Backend-Application/Store-Tokens) in a secure database with proper encryption and access controls in place. Make sure to use a database that supports encryption at rest and in transit to ensure the security of the stored tokens. * **Secrets Management Solutions**: Utilize a specialized secrets management solution, such as HashiCorp Vault or AWS Secrets Manager. These tools provide additional layers of security, access control, and auditing capabilities to ensure the safe storage of your `client_id`, `client_secret`, and `access_token`. * When storing access tokens, also store any relevant metadata, such as the associated employer ID. This will help you maintain data integrity and prevent mixing up tokens across different employers. This topic is covered in more detail in [Store Tokens](/implementation-guide/Backend-Application/Store-Tokens). Finch Developer Dashboard ## Familiarize Yourself With the Finch Developer Dashboard The Finch Developer Dashboard is your centralized place to manage your Finch Applications, view current connections, review request activity, and set up webhook alerts. We will cover these tabs in more detail in the following sections, but here is a quick overview. * Credentials: View your application credentials, including your `client_id` and `client_secret`, and product scopes. * Connections: View the status of your connections, including the last sync time and any errors that occurred. * Integrations: Manage providers that you have integrated with, including the ability to enable or disable specific providers. * Activity: Review the activity log to see a history of requests made by your application, including the request type, status, and timestamp. * Webhooks: Set up webhook alerts to receive notifications when specific events occur, such as a connection error or a successful sync. ## Verify Product Scopes On the Credentials tab, verify the correct products (commonly called “scopes”) are checked that your application will need access to. Products determine the specific data your application can access and the actions it can perform. Each product refers directly to a Finch endpoint. If the products are not correct, reach out to your Implementation Engineer or [developers@tryfinch.com](mailto:developers@tryfinch.com). | Product Scope | Description | API Endpoint | Read/Write | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ---------- | | Company | Company data, such as company legal name, office addresses, or Employer Identification Number (EIN) | `/company` | Read Only | | Directory | List all active and inactive employee employees at the company | `/directory` | Read Only | | Individual | Individual employee data, such as names, contact information, or dates of birth | `/individual` | Read Only | | Employment | Employment data, such as job title, department, start and end dates, or employee income | `/employment` | Read Only | | Payment | Company payroll data, such as payment data, such as payment dates or total amounts | `/payment` | Read Only | | Pay-Statement | Detailed pay statement data, such as gross pay, earnings, employee deductions, or employer contributions. Requires the Payment scope also be selected — there's no supported use case for Pay-Statement alone. | `/pay-statement` | Read Only | | Benefits | Ability to write back employee deductions or employer contributions directly to the employer's provider. This is our Deductions product. | `/benefits` | Read/Write | | Documents | Read company documents such as W4 Forms | `/documents` | Read Only | ## Add Redirect URIs (Optional) if you are using the [Finch Connect Redirect Flow](/implementation-guide/Connect/Set-Up-Finch-Connect#redirect-finch-connect), specify any [Redirect URIs](#redirect-uris) for your application. This URL must be hosted on your own server or a trusted domain. Example: `https://your-trusted-domain.com/api/finch/callback` To authorize with Finch, you'll need to provide one or more redirect URIs. The user will be redirected to the specified URI upon successfully authorizing your application access to their employment system. On redirect, the URI will contain an authorization `code` query parameter that must be exchanged with Finch's authorization server for an access token. Finch's embedded Frontend SDKs don't need to set up a redirect URI. The default redirect URI **`https://tryfinch.com`** is already applied. The redirect URIs must match one of the following formats— | Protocol | Format | Examples | | -------- | --------------------------------------- | ----------------------- | | HTTP | A localhost URI with protocol `http://` | `http://localhost:8000` | | HTTPS | A URI with protocol `https://` | `https://example.com` | *** ## Checkpoint + Next Step After completing this step, you should have registered for a Finch Developer Dashboard account and set up a sandbox application, using your unique `client_id` and `client_secret`. You should also have a clear understanding of the Finch products that your application requires. You now have everything necessary to [Integrate Finch Connect Into Your Application](/implementation-guide/Connect/Set-Up-Finch-Connect) to begin connecting to employment providers. ## Learn more * [Store Access Tokens](/implementation-guide/Backend-Application/Store-Tokens) # Retrieve Access Token Source: https://developer.tryfinch.com/implementation-guide/Connect/Retrieve-Access-Token In this guide, you’ll exchange the authorization code for an access token. Access tokens are required for making API requests to Finch endpoints. Now that you have successfully [integrated Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect) into your application's frontend and obtained an authorization code, you will need to exchange it for an access token. Access tokens are required for making API requests to Finch's various endpoints. In this step, you'll set up a secure server-side process to exchange the authorization code for an access token. 1. **Create a server-side “callback” endpoint**: Set up a secure server-side endpoint in your application to handle the exchange of authorization codes for access tokens. This endpoint should be accessible only by your application's backend to ensure the security of the process. This endpoint will receive the authorization code as a query parameter from your frontend and communicate with Finch's API to obtain the access token. Example: `https://example.com/api/finch/callback`. > You can reuse this same endpoint to support a Redirect Finch Connect flow as well. Just make sure to add the `redirect_uri` to the whitelist in your Finch Developer Dashboard. 2. **Exchange the authorization code for an access token**: In your server-side code, make a POST request to the `/auth/token` endpoint. The request should include the following fields in the request body's JSON payload: * `client_id`: Your unique client ID from the Finch developer dashboard. * `client_secret`: Your unique client secret from the Finch developer dashboard. * `code`: The authorization code obtained from Finch Connect in the [Set Up Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect). * `redirect_uri` (optional): If using the Redirect Finch Connect Flow, include the `redirect_uri`. This is the same redirect URI you used when setting up Finch Connect. If you using Embedded Flow, do not include `redirect_uri` in the payload. ```bash Token exchange example theme={null} curl https://api.tryfinch.com/auth/token \ -X POST \ -H "Content-Type: application/json" \ --data-raw '{ "client_id": "", "client_secret": "", "code": "", }' ``` 3. **Handle the response**: Finch's `/auth/token` endpoint will respond with a JSON object containing an `access_token` if the request is successful. Parse the JSON response body and extract the `access_token`. ```json theme={null} { "company_id": "4ab15e51-11ad-49f4-acae-f343b7794375", "account_id": "ac3a2af9-ce03-46c4-9142-81abe789c64d", "connection_id": "6dab009c-77c8-43d9-8f81-e093f7c65bc1", "provider_id": "gusto", "products": ["directory", "employment", "individual"], "client_type": "production", "connection_type": "provider", "access_token": "7e965183-9332-423c-9259-3edafb332ad2", "customer_id": "1234567890", "token_type": "bearer", "entity_ids": [ "ba9c617b-3446-447a-9dc9-4a8c108ecf2e", "82db13aa-700f-478b-a677-c9177f0b2ac6" ] } ``` 4. **Securely store the access token**: It is critical to store access tokens securely, as they grant access to sensitive user data. Implement a secure storage solution to store access tokens, treating them with the same level of security as passwords. Do not log or expose access tokens to your frontend application. Storing access tokens is covered in more depth in [Store Tokens](/implementation-guide/Backend-Application/Store-Tokens). 5. **Handle errors**: If the `/auth/token` endpoint returns an error, your server-side code should handle it gracefully. Common error scenarios include invalid or expired authorization codes, incorrect client IDs or secrets, or mismatched redirect URIs. Display a helpful error message to the user or retry the authentication flow as needed. *** ## Checkpoint + Next Step After completing this step, your application will be able to exchange authorization codes for access tokens securely and automatically. You are now ready to [test your integration](/implementation-guide/Test/Environments) to ensure your integration is robust and reliable. ## Learn more * [Store Tokens](/implementation-guide/Backend-Application/Store-Tokens) * [Mitigate Errors](/implementation-guide/Backend-Application/Mitigate-Errors) # Create a Finch Connect Session Source: https://developer.tryfinch.com/implementation-guide/Connect/Set-Up-Finch-Connect Set up Finch Connect to collect consent from your customers and begin syncing data from their HR or payroll system. [Finch Connect](/how-finch-works/finch-connect) is the interface your customers will use to provide consent, approve permissions, connect their HR or payroll system, and authenticate. Finch will walk each employer through the appropriate flow based on the provider and [auth method](/implementation-guide/Integration-Preparation/Configure-Auth-Methods). Finch Connect is supported via our [Frontend SDKs](/developer-resources/SDKs) for Javascript and React. You can [embed Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect#embedded-flow) into your application, or set up a [redirect flow](/implementation-guide/Connect/Set-Up-Finch-Connect#redirect-flow). This section requires that you have created a Finch application and have access to a client\_id and client\_secret by completing the [Create a Finch Developer Account](implementation-guide/Connect/Create-Account) section. ## Session Configuration Every flow requires you to create a Finch Connect session with your `client_id` and `client_secret` and is configurable with the following parameters: | Parameter | Required | Description | | ------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customer_id` | true | A unique identifier for your customer. | | `customer_name` | true | The name of your customer. | | `customer_email` | false | The email associated to your customer. | | `products` | true | A space-separated list of permissions your application is requesting access to. See [Product Permissions](/api-reference/development-guides/Permissions) for a list of valid permissions. Please note that SSN is its own product scope. | | `redirect_uri` | redirect only | The URI your user is redirected to after successfully granting your application access to their system. This value must match one of your application's configured [redirect URIs](/implementation-guide/Connect/Create-Account#redirect-uris). | | `integration.provider` | optional | An optional parameter that allows you to bypass the provider selection screen by providing a valid `provider_id` from our list of [Providers](/integrations/providers). | | `integration.auth_method` | optional | An optional parameter that allows you to bypass the provider selection screen by providing a valid `auth_method` for a provider from our list of [Providers](/integrations/providers). | | `sandbox` | false | An optional value that allows users to switch on sandbox mode to connect to test environments. Allowed values: `finch` and `provider`. For more information, read our [testing guide](/implementation-guide/Test/Finch-Sandbox). | | `manual` | false | An optional value which when set to true displays both [Automated and Assisted Providers](/integrations/integration-types) on the selection screen. | | `minutes_to_expire` | false | An optional value which allows you to set the number of minutes the connect session should be valid for. Defaults to 30 days. | | `connection_id` | reauthentication only | A unique identifier created when an employer successfully authenticates through Finch Connect. This ID is only used for reauthentication. You will not have a `connection_id` for the first call. For all reauthentication flows you should include the `connection_id` to avoid duplicate connections being created. | ## Create a Connect Session Using the configuration params described in the above sections, your **backend application** will make a call to [Create a New Connect Session](/api-reference/connect/new-session) `POST /connect/sessions`. When creating the connect session, include your internal customer\_id for your customer, the customer’s name and any of the optional fields listed below. ```js theme={null} import Finch from '@tryfinch/finch-api'; const client = new Finch({ clientId: 'My Client ID', clientSecret: 'My Client Secret', }); async function main() { const createConnectSessionResponse = await finch.connect.sessions.new({ products: ["company", "directory", "individual", "employment", "payment", "pay_statement"], customer_id: customer.id, // Your internal customer ID customer_name: customer.name, // Your customer's name customer_email: customer.email, // The email associated to your customer (optional) integration: { // (optional) provider: 'adp_run', // The provider you wand to show up in connect (optional) auth_method: 'credential' // The auth method of the provider to show up (optional) }, minutes_to_expire: 43200, // How long you want the session to last for (defaults to 30 days) redirect_uri: '' // The URI to redirect to for the redirect connect flow (optional) sandbox: false // create a sandbox session for a sandbox app (optional) manual: false // A value that, when set to true, displays both Automated and Assisted providers on the selection screen (optional) }); /** * { * "session_id": "
", * "connect_url": "" * } **/ console.log(createConnectSessionResponse); } main(); ``` If your customer has successfully authenticated (completed Finch Connect and you see a Live connection on your dashboard) and you call `POST /connect/sessions` using the same `customer_id` you passed in, Finch will prompt you to re-authenticate instead and return the following error: ``` { "code": 400, "finch_code": "connection_already_exists", "message": "There's an existing connection for the customer_id: . Please use the /connect/sessions/reauthenticate endpoint instead.", "name": "bad_request", "context": { "customer_id": "", "connection_id": "" }, } ``` If your customer has not yet successfully authenticated and you call `POST / connect/sessions` using the same `customer_id` you passed in, Finch will simply refresh the connect session and return the same `session_id`. You can do this if you wish to update the Customer Name or any other parameter before your customer connects. If you wish to update any parameters after the customer has connected, you will need to use `POST / connect/sessions/reauthenticate`. ### Best Practices: Creating Sessions #### DO * Always pass in a **stable and unique** `customer_id` for a given employer, and **reuse the same `customer_id` across retries or drop-offs.** Even if an employer opens the Connect session multiple times before successfully connecting, using the same `customer_id` ensures all attempts are tracked as a single staged session. * If you think an employer intends to connect multiple entities or payroll systems, you can append an identifier to the `customer_id` to differentiate the Connect sessions (e.g.: `acme-1`, `acme-2`). Visit this [Help Center article](https://support.tryfinch.com/hc/en-us/articles/31148519242772-FAQs-Connection-ID-Session-ID) for more details. #### DON'T * Avoid generating new `customer_ids` on retries or failed connection attempts - this results in multiple redundant staged connections and could result in unintended behavior: * If an employer converts using Session\_Link\_1, Session\_Link\_2 will eventually expire * If an employer converts using both Session\_Link\_1 and Session\_Link\_2, they will inadvertently create two connections. ### Reauthentication Sessions Your application should be able to generate a Finch Connect session for reathentication. This will avoid creating duplicate connections and ensure that the user is able to reauthenticate successfully to continue syncing data. If a connection goes into a status of `reauth`, you will need to create a reauthentication session. This is done by calling [Create a new Connect session for reauthentication](/api-reference/connect/reauthenticate-session) (`POST /connect/sessions/reauthenticate`) endpoint with the `connection_id` of the connection that requires reauthentication. The response will include a new `session_id` and `connect_url` for the reauthentication session. ## Launch Finch Connect Finch provides two options to launch Finch Connect: redirect and embedded. For both options, your customer will go through the same authentication flow in Finch Connect. When launching either flow, you may optionally pass a state parameter. Finch Connect sessions are created server-side using your client credentials, so they are not vulnerable to the CSRF attacks that `state` is traditionally used to prevent. The `state` parameter is not required, but you may use it to carry context through the authorization code exchange or for additional security requirements specific to your application. **Note that `state` is not a parameter accepted by `POST /connect/sessions` and will be silently ignored if passed — see the redirect and embedded flow sections below for how to include it in each flow.** ### Redirect Flow Use the redirect flow if you are not using the Finch Frontend SDK or need to share a link directly with your customer, such as via email or a URL redirect. 1. **Configure Finch Connect** — Create a connect session using `POST /connect/sessions`. See [Create a Connect Session](#create-a-connect-session) above for details. 2. **Share Finch Connect** — Provide your customer with a link or button pointing to the `connect_url`. Your customer clicks it to redirect their browser to Finch Connect, hosted by Finch at `https://connect.tryfinch.com`, and initiate the authorization flow. 3. **Request access** — Finch Connect prompts your customer to approve the permissions your application is requesting and provide the credentials or information needed to connect their employment system. 4. **Retrieve the authorization code** — After your customer authenticates and grants access, Finch Connect redirects their browser to your `redirect_uri` with a short-lived authorization `code`. 5. **Exchange the code for an access token** — Your application exchanges the short-lived `code` for a long-lived `access_token`. See [Retrieve An Access Token](/implementation-guide/Connect/Retrieve-Access-Token) for details. The `access_token` is then used to make Finch API calls. The `connect_url` supports an optional `state` parameter, which will be returned as-is to your `redirect_uri` after your customer authenticates. To use it, append it to the URL: ``` https://connect.tryfinch.com/authorize?session=&state=foo ``` Finch Connect sessions are created server-side using your client credentials, so they are not vulnerable to the CSRF attacks that state is traditionally used to prevent. The state parameter is not required, but you may use it to carry context through the authorization code exchange or for additional security purposes specific to your application. ### Embedded Flow Use the embedded flow if you are integrating via the Finch Frontend SDK and want your customer to complete the authorization flow within your application. 1. **Configure Finch Connect** — Create a connect session using `POST /connect/sessions`. See [Create a Connect Session](#create-a-connect-session) above for details. 2. **Share Finch Connect** — Provide your customer with a button that calls `connect.open()` with the `session_id`. Your customer clicks it to launch the Connect modal within your application and initiate the authorization flow. 3. **Request access** — Finch Connect prompts your customer to approve the permissions your application is requesting and provide the credentials or information needed to connect their employment system. 4. **Retrieve the authorization code** — Your application receives a short-lived authorization `code` via the SDK's `onSuccess` callback after your customer successfully authenticates. 5. **Exchange the code for an access token** — Your application exchanges the short-lived `code` for a long-lived `access_token`. See [Retrieve An Access Token](/implementation-guide/Connect/Retrieve-Access-Token) for details. The `access_token` is then used to make Finch API calls. The `open` call accepts an optional `state` parameter if you need to carry context through the authorization flow: ```js theme={null} connect.open({ sessionId, state }); ``` We offer both a JavaScript and React frontend SDK, both of which can be viewed at the repository below. See the README in the repository for installation and usage instructions. *** ## Checkpoint + Next Step After completing this step, you will have successfully integrated Finch Connect into your application's front end. This will enable users to authenticate with their employment systems, providing your application with the necessary authorization to [Retrieve An Access Token](/implementation-guide/Connect/Retrieve-Access-Token) in the next section. ## Learn more * [Finch Connect Best Practices](/implementation-guide/Deploy-and-Manage/Increase-Employer-Adoption) # Increase Employer Adoption Source: https://developer.tryfinch.com/implementation-guide/Deploy-and-Manage/Increase-Employer-Adoption Best practices for improving employer completion rates in Finch Connect through in-app messaging, UI defaults, and re-engagement at key decision points. Finch Connect is an embeddable UI that employers use to connect their employment system to your application, approve permissions, select their provider, and authorize access. > New to Finch Connect or looking for help getting started? Read the [Finch Overview](/how-finch-works/finch-overview). Apply the following best practices when implementing Finch Connect to maximize employer completion rates. ## 1. Set Finch Connect as the default integration option Present Finch Connect as the primary option rather than listing it alongside manual flows as equal alternatives. Give it visual prominence through size, positioning, and a label like "Recommended" or "Preferred". Any manual alternatives should be clearly secondary. Finch Connect Best Practices 1.jpg ## 2. Communicate the value of connecting The value for employers will depend on your use case, but may include: * **Save time:** Finch is easy to set up, and eliminates the need to create or reformat any files. * **Enable automation:** Automatically share updates with us each day or week. * **More accurate:** Avoid common errors (eg. typos, formatting errors, corrupted files, etc.). > 💡 **Tip:** Finch's [Sales & Marketing Best Practices](https://support.tryfinch.com/collections/5213481409-for-sales-%26-marketing) collection includes ready-to-use messaging examples for different employer types and use cases. Available on Starter, Pro, and Premier plans. Finch Connect Best Practices 4.jpg ## 3. Set expectations before the connection flow Before employers open Finch Connect, give them the context they need to proceed confidently. ### Tell the employer what to expect Before launching Finch Connect, tell the employer they'll connect their payroll or HRIS system, what data your app will access, and why. If credentials aren't available, offer a 'skip and come back later' option and prompt them to [connect later](#4-create-multiple-opportunities-to-connect). Finch Connect guides employers through their provider's authentication flow — including credential entry, OAuth steps, and other provider-specific requirements. You don't need to send separate setup instructions or build per-provider guidance. Finch handles authentication differences across all supported providers directly in the UI. ### Emphasize data security Let employers know that Finch encrypts all data in transit and at rest. Share the [What is Finch? FAQ for Employers](https://www.tryfinch.com/for-employers) with employers who have further questions. Clarify that your app does not have access to their credentials, and that they can disconnect at any time. Link to [Finch's Trust Center](https://finch.secureframetrust.com/#resources) for additional detail. ## 4. Create multiple opportunities to connect If an employer does not connect their employment system during onboarding, remind them to return. Use in-app messaging or email automations to prompt reconnection and explain the value. These same channels can notify employers when re-authentication is needed. ## 5. Deploy Finch Connect early in the onboarding process Authorization through Finch Connect completes quickly, but the initial data sync job can take time depending on the provider and data volume. Embed Finch Connect early in onboarding so the sync runs in parallel while employers complete other setup steps. While the data sync job is running, continue onboarding — collect additional information or show a product tutorial. Finch Connect Best Practices 2.jpg Once the employer connects, Finch begins the initial data sync. Listen for the `job.initial_data_sync_org` and `job.initial_data_sync_payroll` webhook events to know when each sync completes — at that point, the corresponding Finch data endpoints are available for that connection. See [Webhooks](/developer-resources/Webhooks) for setup and event details. ## 6. Bypass the provider selection screen If your application already has a place where employers select or manage their integrations, you can pass the provider directly to Finch Connect instead of using the built-in selection screen. Pass a valid provider ID in the `integration.provider` field when creating the Connect session. See the [Providers](/api-reference/management/providers) endpoint for a full list of valid provider IDs. Omit `integration` to use the default Finch Connect provider selection screen. ```js Bypass Enabled theme={null} const session = await finch.connect.sessions.new({ products: ["company", "directory", "individual", "employment", "payment", "pay_statement"], customer_id: customer.id, customer_name: customer.name, integration: { provider: "gusto" } }); ``` ```js Bypass Disabled theme={null} const session = await finch.connect.sessions.new({ products: ["company", "directory", "individual", "employment", "payment", "pay_statement"], customer_id: customer.id, customer_name: customer.name }); ``` Finch Connect Best Practices 3.jpg *** ## Checkpoint + Next Step Your application now has the messaging, defaults, and re-engagement flows in place to guide employers through Finch Connect and increase completion rates. For technical questions, the [Support](/implementation-guide/Deploy-and-Manage/Support) page covers how to reach the Finch support team. ## Learn more * [What is Finch? FAQ for Employers](https://www.tryfinch.com/for-employers) # Get support Source: https://developer.tryfinch.com/implementation-guide/Deploy-and-Manage/Support Reach Finch Technical Support via email, Slack, or the support portal. Include request_id and other identifiers in your ticket for faster, accurate responses. ## Information to include in support requests Include the following in your support request — the more context you can provide, the faster we can help: | Field | Description | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `request_id` | Returned in the response header of every API request. | | `company_id` | Associated with the access token. Available in the developer dashboard or from the `/company` or `/introspect` endpoints. | | `job_id` | For Deductions requests only. Returned after calling the benefits endpoints. | | `individual_id` | The Finch-generated ID returned from the `/directory` endpoint. Required when asking about specific pay statements or individuals. | | `benefit_id` | The Finch-generated ID returned from the `/benefits` endpoint. Required when asking about specific benefits. | ## How to contact support You can reach the support team via email, Slack, or the [support portal](https://support.tryfinch.com/hc/en-us). The team is available Monday–Friday, 9 am–8 pm EST and responds to requests within 24 hours. ### Support portal When you submit a ticket through the portal, you'll receive an email confirmation with a ticket number you can use to track your request. ### Email You can email the support team at [developers@tryfinch.com](mailto:developers@tryfinch.com). ### Slack If you're on a Pro or Premier plan, you can tag the support team in your shared Slack channel using @FinchSupport. ### Developer Success Engineer If you're on a Pro or Premier plan, you're assigned a dedicated Developer Success Engineer (DSE) as your primary point of contact for technical questions and integration support. # Configure Auth Methods Source: https://developer.tryfinch.com/implementation-guide/Integration-Preparation/Configure-Auth-Methods Learn more about the four authentication methods offered by Finch -- OAuth, Credentials, API token, and Assisted. In this guide, we’ll cover everything you need to know about Finch’s Authentication Methods, including Authentication Fallback and Re-authentication. ## Authentication Methods Finch offers 4 ways for employers to authenticate through Finch Connect: OAuth, Credentials, API Token, or Assisted. Authentication method will vary by provider, and will impact the fields and functionality available to you. Find field support for each provider by authentication method [here](/integrations/field-support). ### OAuth **OAuth** allows access tokens to be securely issued to Finch via the provider’s own authorization flow. This is the preferred authentication method for all parties. Finch is constantly working to increase the number of providers supported through OAuth, which offers superior speed and survivability. However, OAuth support is heavily dependent on the underlying provider. ### Credentials The **credentials** method enables employers to simply log in with an administrator username and password to set up a connection. It’s a very low friction option for employers to connect their provider through Finch. When possible, Finch will automatically set up a separate third-party administrator or accountant user behind the scenes to keep this connection active indefinitely. This will be noted on the credentials log in screen. If for some reason an employer is unable to log in with credentials after 3 attempts, they can still establish a connection through [Authentication Fallback](/implementation-guide/Integration-Preparation/Configure-Auth-Methods#set-up-authentication-fallback). ### API Token The **API token** method leverages API keys supplied by the provider to establish a connection. Once set up, these connections very rarely need [re-authentication](/implementation-guide/Integration-Preparation/Configure-Auth-Methods#manage-re-authentication). Finch will guide employers through each step required to obtain an API key from their provider. See our [authentication guides](https://support.tryfinch.com/collections/9565019353-authentication-guides) for details. In a few cases, employers will be charged for access to their API token. If you have a Help Center login, you can see the (short) list of providers that charge employer fees [here](https://support.tryfinch.com/hc/en-us/articles/25312473665428-Costs-Fees-for-Employers). ### Assisted **Assisted** is an authentication method available to customers using [Finch Assist](/integrations/integration-types#assisted-integrations). In this method, Finch asks employers to create a new admin or accountant user in their system. Finch’s operations team then uses that connection to refresh data every 7 days. [Re-authentication](/implementation-guide/Integration-Preparation/Configure-Auth-Methods#manage-re-authentication) will only be required if the user is removed or loses the necessary permissions. ## Set Up Preferred Authentication Methods Per Provider While authentication method will often come down to which fields or functionality is needed, you have the flexibility to decide which to make available for your end customers and their order of priority. You can set primary and secondary authentication methods for each provider, and even hide specific methods if desired. All of this is possible through the Finch Dashboard. For example, if you want to present only the API token method to Bob customers, Finch can conceal the credentials-based authentication method in Finch Connect. ## Enable or Disable Authentication Methods Globally You can also disable an authentication method globally using the Settings page in the Dashboard. These settings will apply automatically to any new integrations. ## Set Up Authentication Fallback Authentication Fallback enables employers to authorize through Finch Connect even when Finch is experiencing intermittent issues with a provider. Please note [Email Forwarding](/implementation-guide/Integration-Preparation/Email-Forwarding) is a prerequisite for Authentication Fallback. Please refer to this [Help Center article](https://support.tryfinch.com/hc/en-us/articles/28708518221204-Authentication-with-Auth-Fallback) for recommendations on how to best manage connections created through Authentication Fallback. Fallback If Authentication Fallback is enabled, Finch Connect will still attempt to authenticate with Credentials first. If this fails, Finch Connect will prompt the employer to set up Finch as a third-party administrator in their HRIS or payroll system using a set of manual instructions. Depending on the provider this can happen by default, or after a set number of failed attempts. Until Finch processes this invitation, you will receive a 202 response code when making requests with the token. Once Finch has established the connection, data will flow through the Finch API just like any other automated connection. Authentication Fallback can be enabled for the following providers: * ADP Workforce Now * ADP Run * Quickbooks * Paychex * Paycom * Sequoia One * Square Payroll To enable Authentication Fallback, please reach out to your Developer Success Representative. You will need to set up [Email Forwarding](/implementation-guide/Integration-Preparation/Email-Forwarding) and ensure your application is configured to handle 202 response codes from Finch. ## Manage Re-Authentication Finch aims to maintain connections as long as possible. However, there are a few situations where connections may be broken. For example, connections may be broken if a user changes security settings or permissions on their account. Or if an underlying provider makes a breaking change to their infrastructure. If this happens, the employer will need to go through Finch Connect again (re-authenticate). The `connection_id` parameter allows the employer to bypass the steps of Finch Connect they’ve already completed when re-authenticating. Remember this will create a new **`access_token`** for your user that will be to be updated. Make sure to save this new token in your database. ### Identify connections that require re-authentication In the API, broken connections will result in an error with the HTTP status code **`401`** and a **`finch_code`** of **`reauthenticate_user`.** In the Finch Dashboard, you can view all connections that require re-authentication on the Connections page. If any connections require re-authentication, a banner will appear at the top of the page. Simply click the banner to filter the connections that require action from the employer. ### Set up re-auth notifications To increase conversion, we recommend either using in-app or email notifications to notify your user there is an issue with their connection, why re-connecting is beneficial, and the steps they need to follow to re-connect. To create a more seamless experience and avoid unintended duplicate connections, use the `connection_id` parameter. You can find the `connection_id` of your customer by calling the **[/introspect](/api-reference/management/introspect)** endpoint with their **`access_token`**. Below are a couple of options to present the re-connection flow to your users: 1. Prompt your user to log on to their application dashboard where you can present them the UI to go through Finch Connect again. 2. Send your user an authorization URL with a **`redirect_uri`** that redirects them back to their application dashboard after a successful reconnection. Learn more about **[redirecting your users to Finch Connect](/implementation-guide/Connect/Set-Up-Finch-Connect)**. # Email Forwarding Source: https://developer.tryfinch.com/implementation-guide/Integration-Preparation/Email-Forwarding Set up email forwarding to ensure successful authentication with providers. ## Email Forwarding Email forwarding is required for all assisted integrations. Our automated integrations also use the email forwarding address when setting up accountant accounts for providers that require an accountant user to be set up in order to access data. In the case that you have not setup email forwarding, the automated integrations will use our standard Finch payroll email address. More information about email forwarding is in our Help Center article, [Why do I need to set up email forwarding?](https://support.tryfinch.com/hc/en-us/articles/24177472738324-Why-do-I-need-to-set-up-email-forwarding). Directions for setting up email forwarding can be found in our Help Center article, [Email Forwarding Setup](https://support.tryfinch.com/hc/en-us/articles/27241619992980-Email-Forwarding-Setup-Overview). # Manage Integrations Source: https://developer.tryfinch.com/implementation-guide/Integration-Preparation/Manage-Integrations Customize the list of Providers your customers see in Finch Connect. Validate field support for each provider you plan to use, and disable any that don't fit your use case. ## Manage Integrations in the Developer Dashboard The Integrations tab of the Dashboard is where you can manage the providers that are available to your customers in Finch Connect. You can enable or disable providers, customize the order in which providers are displayed, and preview changes in Finch Connect.