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: