diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index f7014c35..a7130553 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.11.0"
+ ".": "0.12.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f80222bc..1849642f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 0.12.0 (2024-01-12)
+
+Full Changelog: [v0.11.0...v0.12.0](https://github.com/Finch-API/finch-api-python/compare/v0.11.0...v0.12.0)
+
+### Features
+
+* **webhooks:** add types to the `unwrap` method ([#258](https://github.com/Finch-API/finch-api-python/issues/258)) ([9687a1e](https://github.com/Finch-API/finch-api-python/commit/9687a1e19097f89f1d671bac0d8c29496ab9c9f5))
+
+
+### Documentation
+
+* **readme:** improve api reference ([#260](https://github.com/Finch-API/finch-api-python/issues/260)) ([09ddece](https://github.com/Finch-API/finch-api-python/commit/09ddeceee4622e4f9ac9ac6f8eaa3ac3eb23a9e4))
+
## 0.11.0 (2024-01-11)
Full Changelog: [v0.10.0...v0.11.0](https://github.com/Finch-API/finch-api-python/compare/v0.10.0...v0.11.0)
diff --git a/README.md b/README.md
index 89067751..2e258279 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ and offers both synchronous and asynchronous clients powered by [httpx](https://
## Documentation
-The API documentation can be found [in the Finch Documentation Center](https://developer.tryfinch.com/).
+The REST API documentation can be found [in the Finch Documentation Center](https://developer.tryfinch.com/). The full API of this library can be found in [api.md](https://www.github.com/Finch-API/finch-api-python/blob/main/api.md).
## Installation
diff --git a/api.md b/api.md
index 62d3fb7c..21650e84 100644
--- a/api.md
+++ b/api.md
@@ -179,9 +179,26 @@ Methods:
# Webhooks
+Types:
+
+```python
+from finch.types import (
+ AccountUpdateEvent,
+ BaseWebhookEvent,
+ CompanyEvent,
+ DirectoryEvent,
+ EmploymentEvent,
+ IndividualEvent,
+ JobCompletionEvent,
+ PayStatementEvent,
+ PaymentEvent,
+ WebhookEvent,
+)
+```
+
Methods:
-- client.webhooks.unwrap(\*args) -> object
+- client.webhooks.unwrap(\*args) -> WebhookEvent
- client.webhooks.verify_signature(\*args) -> None
# RequestForwarding
diff --git a/pyproject.toml b/pyproject.toml
index 8e77530a..fd13bc7d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "finch-api"
-version = "0.11.0"
+version = "0.12.0"
description = "The official Python library for the Finch API"
readme = "README.md"
license = "Apache-2.0"
diff --git a/src/finch/_version.py b/src/finch/_version.py
index 81d4eb27..418bd1f8 100644
--- a/src/finch/_version.py
+++ b/src/finch/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless.
__title__ = "finch"
-__version__ = "0.11.0" # x-release-please-version
+__version__ = "0.12.0" # x-release-please-version
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
index 6d68645f..6f6d5b93 100644
--- a/src/finch/resources/webhooks.py
+++ b/src/finch/resources/webhooks.py
@@ -7,14 +7,17 @@
import math
import base64
import hashlib
+from typing import cast
from datetime import datetime, timezone, timedelta
+from ..types import WebhookEvent
from .._types import (
HeadersLike,
)
from .._utils import (
get_required_header,
)
+from .._models import construct_type
from .._resource import SyncAPIResource, AsyncAPIResource
__all__ = ["Webhooks", "AsyncWebhooks"]
@@ -27,10 +30,16 @@ def unwrap(
headers: HeadersLike,
*,
secret: str | None = None,
- ) -> object:
+ ) -> WebhookEvent:
"""Validates that the given payload was sent by Finch and parses the payload."""
self.verify_signature(payload=payload, headers=headers, secret=secret)
- return json.loads(payload)
+ return cast(
+ WebhookEvent,
+ construct_type(
+ value=json.loads(payload),
+ type_=WebhookEvent, # type: ignore[arg-type]
+ ),
+ )
def verify_signature(
self,
@@ -120,10 +129,16 @@ def unwrap(
headers: HeadersLike,
*,
secret: str | None = None,
- ) -> object:
+ ) -> WebhookEvent:
"""Validates that the given payload was sent by Finch and parses the payload."""
self.verify_signature(payload=payload, headers=headers, secret=secret)
- return json.loads(payload)
+ return cast(
+ WebhookEvent,
+ construct_type(
+ value=json.loads(payload),
+ type_=WebhookEvent, # type: ignore[arg-type]
+ ),
+ )
def verify_signature(
self,
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index 3519a122..da3b0ba0 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -14,9 +14,19 @@
from .provider import Provider as Provider
from .money_param import MoneyParam as MoneyParam
from .income_param import IncomeParam as IncomeParam
+from .company_event import CompanyEvent as CompanyEvent
from .introspection import Introspection as Introspection
+from .payment_event import PaymentEvent as PaymentEvent
+from .webhook_event import WebhookEvent as WebhookEvent
from .location_param import LocationParam as LocationParam
+from .directory_event import DirectoryEvent as DirectoryEvent
+from .employment_event import EmploymentEvent as EmploymentEvent
+from .individual_event import IndividualEvent as IndividualEvent
+from .base_webhook_event import BaseWebhookEvent as BaseWebhookEvent
from .disconnect_response import DisconnectResponse as DisconnectResponse
+from .pay_statement_event import PayStatementEvent as PayStatementEvent
+from .account_update_event import AccountUpdateEvent as AccountUpdateEvent
+from .job_completion_event import JobCompletionEvent as JobCompletionEvent
from .access_token_create_params import AccessTokenCreateParams as AccessTokenCreateParams
from .create_access_token_response import CreateAccessTokenResponse as CreateAccessTokenResponse
from .request_forwarding_forward_params import RequestForwardingForwardParams as RequestForwardingForwardParams
diff --git a/src/finch/types/account_update_event.py b/src/finch/types/account_update_event.py
new file mode 100644
index 00000000..e87a6997
--- /dev/null
+++ b/src/finch/types/account_update_event.py
@@ -0,0 +1,413 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .hris import BenefitsSupport
+from .shared import ConnectionStatusType
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = [
+ "AccountUpdateEvent",
+ "AccountUpdateEventData",
+ "AccountUpdateEventDataAuthenticationMethod",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFields",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompany",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyAccounts",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartments",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartmentsParent",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyEntity",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyLocations",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectory",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividuals",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividualsManager",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryPaging",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmployment",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentDepartment",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentEmployment",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentIncome",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentLocation",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentManager",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividual",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualEmails",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualPhoneNumbers",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualResidence",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatement",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPaging",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatements",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEarnings",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployeeDeductions",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayment",
+ "AccountUpdateEventDataAuthenticationMethodSupportedFieldsPaymentPayPeriod",
+]
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyAccounts(BaseModel):
+ account_name: Optional[bool] = None
+
+ account_number: Optional[bool] = None
+
+ account_type: Optional[bool] = None
+
+ institution_name: Optional[bool] = None
+
+ routing_number: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartmentsParent(BaseModel):
+ name: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartments(BaseModel):
+ name: Optional[bool] = None
+
+ parent: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartmentsParent] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyEntity(BaseModel):
+ subtype: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyLocations(BaseModel):
+ city: Optional[bool] = None
+
+ country: Optional[bool] = None
+
+ line1: Optional[bool] = None
+
+ line2: Optional[bool] = None
+
+ postal_code: Optional[bool] = None
+
+ state: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompany(BaseModel):
+ id: Optional[bool] = None
+
+ accounts: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyAccounts] = None
+
+ departments: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyDepartments] = None
+
+ ein: Optional[bool] = None
+
+ entity: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyEntity] = None
+
+ legal_name: Optional[bool] = None
+
+ locations: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompanyLocations] = None
+
+ primary_email: Optional[bool] = None
+
+ primary_phone_number: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividualsManager(BaseModel):
+ id: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividuals(BaseModel):
+ id: Optional[bool] = None
+
+ department: Optional[bool] = None
+
+ first_name: Optional[bool] = None
+
+ is_active: Optional[bool] = None
+
+ last_name: Optional[bool] = None
+
+ manager: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividualsManager] = None
+
+ middle_name: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryPaging(BaseModel):
+ count: Optional[bool] = None
+
+ offset: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectory(BaseModel):
+ individuals: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryIndividuals] = None
+
+ paging: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectoryPaging] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentDepartment(BaseModel):
+ name: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentEmployment(BaseModel):
+ subtype: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentIncome(BaseModel):
+ amount: Optional[bool] = None
+
+ currency: Optional[bool] = None
+
+ unit: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentLocation(BaseModel):
+ city: Optional[bool] = None
+
+ country: Optional[bool] = None
+
+ line1: Optional[bool] = None
+
+ line2: Optional[bool] = None
+
+ postal_code: Optional[bool] = None
+
+ state: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentManager(BaseModel):
+ id: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmployment(BaseModel):
+ id: Optional[bool] = None
+
+ class_code: Optional[bool] = None
+
+ custom_fields: Optional[bool] = None
+
+ department: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentDepartment] = None
+
+ employment: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentEmployment] = None
+
+ end_date: Optional[bool] = None
+
+ first_name: Optional[bool] = None
+
+ income_history: Optional[bool] = None
+
+ income: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentIncome] = None
+
+ is_active: Optional[bool] = None
+
+ last_name: Optional[bool] = None
+
+ location: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentLocation] = None
+
+ manager: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmploymentManager] = None
+
+ middle_name: Optional[bool] = None
+
+ start_date: Optional[bool] = None
+
+ title: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualEmails(BaseModel):
+ data: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualPhoneNumbers(BaseModel):
+ data: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualResidence(BaseModel):
+ city: Optional[bool] = None
+
+ country: Optional[bool] = None
+
+ line1: Optional[bool] = None
+
+ line2: Optional[bool] = None
+
+ postal_code: Optional[bool] = None
+
+ state: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividual(BaseModel):
+ id: Optional[bool] = None
+
+ dob: Optional[bool] = None
+
+ emails: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualEmails] = None
+
+ encrypted_ssn: Optional[bool] = None
+
+ ethnicity: Optional[bool] = None
+
+ first_name: Optional[bool] = None
+
+ gender: Optional[bool] = None
+
+ last_name: Optional[bool] = None
+
+ middle_name: Optional[bool] = None
+
+ phone_numbers: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualPhoneNumbers] = None
+
+ preferred_name: Optional[bool] = None
+
+ residence: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividualResidence] = None
+
+ ssn: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPaging(BaseModel):
+ count: bool
+
+ offset: bool
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEarnings(BaseModel):
+ amount: Optional[bool] = None
+
+ currency: Optional[bool] = None
+
+ name: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployeeDeductions(BaseModel):
+ amount: Optional[bool] = None
+
+ currency: Optional[bool] = None
+
+ name: Optional[bool] = None
+
+ pre_tax: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions(BaseModel):
+ amount: Optional[bool] = None
+
+ currency: Optional[bool] = None
+
+ name: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes(BaseModel):
+ amount: Optional[bool] = None
+
+ currency: Optional[bool] = None
+
+ employer: Optional[bool] = None
+
+ name: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatements(BaseModel):
+ earnings: Optional[
+ AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEarnings
+ ] = None
+
+ employee_deductions: Optional[
+ AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployeeDeductions
+ ] = None
+
+ employer_deductions: Optional[
+ AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions
+ ] = None
+
+ gross_pay: Optional[bool] = None
+
+ individual_id: Optional[bool] = None
+
+ net_pay: Optional[bool] = None
+
+ payment_method: Optional[bool] = None
+
+ taxes: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes] = None
+
+ total_hours: Optional[bool] = None
+
+ type: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatement(BaseModel):
+ paging: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPaging] = None
+
+ pay_statements: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatements] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPaymentPayPeriod(BaseModel):
+ end_date: Optional[bool] = None
+
+ start_date: Optional[bool] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayment(BaseModel):
+ id: Optional[bool] = None
+
+ company_debit: Optional[bool] = None
+
+ debit_date: Optional[bool] = None
+
+ employee_taxes: Optional[bool] = None
+
+ employer_taxes: Optional[bool] = None
+
+ gross_pay: Optional[bool] = None
+
+ individual_ids: Optional[bool] = None
+
+ net_pay: Optional[bool] = None
+
+ pay_date: Optional[bool] = None
+
+ pay_period: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPaymentPayPeriod] = None
+
+
+class AccountUpdateEventDataAuthenticationMethodSupportedFields(BaseModel):
+ company: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsCompany] = None
+
+ directory: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsDirectory] = None
+
+ employment: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsEmployment] = None
+
+ individual: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsIndividual] = None
+
+ pay_statement: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatement] = None
+
+ payment: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayment] = None
+
+
+class AccountUpdateEventDataAuthenticationMethod(BaseModel):
+ benefits_support: Optional[BenefitsSupport] = None
+ """Each benefit type and their supported features.
+
+ If the benefit type is not supported, the property will be null
+ """
+
+ supported_fields: Optional[AccountUpdateEventDataAuthenticationMethodSupportedFields] = None
+ """The supported data fields returned by our HR and payroll endpoints"""
+
+ type: Optional[Literal["assisted", "credential", "api_token", "api_credential", "oauth"]] = None
+ """The type of authentication method."""
+
+
+class AccountUpdateEventData(BaseModel):
+ authentication_method: AccountUpdateEventDataAuthenticationMethod
+
+ status: ConnectionStatusType
+
+
+class AccountUpdateEvent(BaseWebhookEvent):
+ data: Optional[AccountUpdateEventData] = None
+
+ event_type: Optional[Literal["account.updated"]] = None
diff --git a/src/finch/types/base_webhook_event.py b/src/finch/types/base_webhook_event.py
new file mode 100644
index 00000000..efdc2818
--- /dev/null
+++ b/src/finch/types/base_webhook_event.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from .._models import BaseModel
+
+__all__ = ["BaseWebhookEvent"]
+
+
+class BaseWebhookEvent(BaseModel):
+ account_id: str
+ """Unique Finch id of the employer account that was used to make this connection."""
+
+ company_id: str
+ """Unique Finch id of the company for which data has been updated."""
diff --git a/src/finch/types/company_event.py b/src/finch/types/company_event.py
new file mode 100644
index 00000000..65c29060
--- /dev/null
+++ b/src/finch/types/company_event.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Dict, Optional
+from typing_extensions import Literal
+
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["CompanyEvent"]
+
+
+class CompanyEvent(BaseWebhookEvent):
+ data: Optional[Dict[str, object]] = None
+
+ event_type: Optional[Literal["company.updated"]] = None
diff --git a/src/finch/types/directory_event.py b/src/finch/types/directory_event.py
new file mode 100644
index 00000000..863a6b43
--- /dev/null
+++ b/src/finch/types/directory_event.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["DirectoryEvent", "DirectoryEventData"]
+
+
+class DirectoryEventData(BaseModel):
+ individual_id: Optional[str] = None
+ """The ID of the individual related to the event."""
+
+
+class DirectoryEvent(BaseWebhookEvent):
+ data: Optional[DirectoryEventData] = None
+
+ event_type: Optional[Literal["directory.created", "directory.updated", "directory.deleted"]] = None
diff --git a/src/finch/types/employment_event.py b/src/finch/types/employment_event.py
new file mode 100644
index 00000000..09d95428
--- /dev/null
+++ b/src/finch/types/employment_event.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["EmploymentEvent", "EmploymentEventData"]
+
+
+class EmploymentEventData(BaseModel):
+ individual_id: Optional[str] = None
+ """The ID of the individual related to the event."""
+
+
+class EmploymentEvent(BaseWebhookEvent):
+ data: Optional[EmploymentEventData] = None
+
+ event_type: Optional[Literal["employment.created", "employment.updated", "employment.deleted"]] = None
diff --git a/src/finch/types/individual_event.py b/src/finch/types/individual_event.py
new file mode 100644
index 00000000..0d51c89b
--- /dev/null
+++ b/src/finch/types/individual_event.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["IndividualEvent", "IndividualEventData"]
+
+
+class IndividualEventData(BaseModel):
+ individual_id: Optional[str] = None
+ """The ID of the individual related to the event."""
+
+
+class IndividualEvent(BaseWebhookEvent):
+ data: Optional[IndividualEventData] = None
+
+ event_type: Optional[Literal["individual.created", "individual.updated", "individual.deleted"]] = None
diff --git a/src/finch/types/job_completion_event.py b/src/finch/types/job_completion_event.py
new file mode 100644
index 00000000..3f77efb0
--- /dev/null
+++ b/src/finch/types/job_completion_event.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["JobCompletionEvent", "JobCompletionEventData"]
+
+
+class JobCompletionEventData(BaseModel):
+ job_id: str
+ """The id of the job which has completed."""
+
+ job_url: str
+ """The url to query the result of the job."""
+
+
+class JobCompletionEvent(BaseWebhookEvent):
+ data: Optional[JobCompletionEventData] = None
+
+ event_type: Optional[
+ Literal[
+ "job.benefit_create.updated",
+ "job.benefit_enroll.updated",
+ "job.benefit_register.updated",
+ "job.benefit_unenroll.updated",
+ "job.benefit_update.updated",
+ "job.data_sync_all.updated",
+ ]
+ ] = None
diff --git a/src/finch/types/pay_statement_event.py b/src/finch/types/pay_statement_event.py
new file mode 100644
index 00000000..b748e459
--- /dev/null
+++ b/src/finch/types/pay_statement_event.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["PayStatementEvent", "PayStatementEventData"]
+
+
+class PayStatementEventData(BaseModel):
+ individual_id: Optional[str] = None
+ """The ID of the individual associated with the pay statement."""
+
+ payment_id: Optional[str] = None
+ """The ID of the payment associated with the pay statement."""
+
+
+class PayStatementEvent(BaseWebhookEvent):
+ data: Optional[PayStatementEventData] = None
+
+ event_type: Optional[Literal["pay_statement.created", "pay_statement.updated", "pay_statement.deleted"]] = None
diff --git a/src/finch/types/payment_event.py b/src/finch/types/payment_event.py
new file mode 100644
index 00000000..dab1cebd
--- /dev/null
+++ b/src/finch/types/payment_event.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .base_webhook_event import BaseWebhookEvent
+
+__all__ = ["PaymentEvent", "PaymentEventData"]
+
+
+class PaymentEventData(BaseModel):
+ pay_date: str
+ """The date of the payment."""
+
+ payment_id: str
+ """The ID of the payment."""
+
+
+class PaymentEvent(BaseWebhookEvent):
+ data: Optional[PaymentEventData] = None
+
+ event_type: Optional[Literal["payment.created", "payment.updated", "payment.deleted"]] = None
diff --git a/src/finch/types/webhook_event.py b/src/finch/types/webhook_event.py
new file mode 100644
index 00000000..ded9cf4e
--- /dev/null
+++ b/src/finch/types/webhook_event.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Union
+
+from .company_event import CompanyEvent
+from .payment_event import PaymentEvent
+from .directory_event import DirectoryEvent
+from .employment_event import EmploymentEvent
+from .individual_event import IndividualEvent
+from .pay_statement_event import PayStatementEvent
+from .account_update_event import AccountUpdateEvent
+from .job_completion_event import JobCompletionEvent
+
+__all__ = ["WebhookEvent"]
+
+WebhookEvent = Union[
+ AccountUpdateEvent,
+ JobCompletionEvent,
+ CompanyEvent,
+ DirectoryEvent,
+ EmploymentEvent,
+ IndividualEvent,
+ PaymentEvent,
+ PayStatementEvent,
+]
diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py
index 250d3a22..203deb9c 100644
--- a/tests/api_resources/test_webhooks.py
+++ b/tests/api_resources/test_webhooks.py
@@ -9,6 +9,7 @@
import pytest
import time_machine
+from pydantic import BaseModel
from finch import Finch, AsyncFinch
from finch._client import Finch, AsyncFinch
@@ -40,7 +41,8 @@ def test_unwrap(self) -> None:
headers = self.headers
secret = self.secret
- self.strict_client.webhooks.unwrap(payload, headers, secret=secret)
+ obj = self.strict_client.webhooks.unwrap(payload, headers, secret=secret)
+ assert isinstance(obj, BaseModel)
@time_machine.travel(fake_now)
def test_verify_signature(self) -> None:
@@ -140,7 +142,8 @@ def test_unwrap(self) -> None:
headers = self.headers
secret = self.secret
- self.strict_client.webhooks.unwrap(payload, headers, secret=secret)
+ obj = self.strict_client.webhooks.unwrap(payload, headers, secret=secret)
+ assert isinstance(obj, BaseModel)
@time_machine.travel(fake_now)
def test_verify_signature(self) -> None: