From 740fdf1dc890eae5ab8d2e62ff6f8321b0ef6e16 Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:40:35 +0000 Subject: [PATCH 1/4] feat(pipes)!: Change Pipes API surface --- .../models/create_connected_account_state.py | 8 + ...te_organization_connected_account_state.py | 8 + ...als_connection_request_connection_owner.py | 10 + ..._credentials_request_2_connection_owner.py | 10 + .../organization_connected_account_state.py | 8 + ...nt_credentials_request_connection_owner.py | 10 + src/workos/pipes/_resource.py | 333 ++++++++++++++---- src/workos/pipes/models/__init__.py | 29 ++ .../pipes/models/connected_account_input.py | 64 ++++ .../pipes/models/create_connected_account.py | 69 ++++ .../create_organization_connected_account.py | 73 ++++ .../data_integration_credentials_response.py | 8 +- .../data_integration_vended_credential.py | 70 ++++ ...e_client_credentials_connection_request.py | 77 ++++ ...tions_upsert_client_credentials_request.py | 5 - ...ons_upsert_client_credentials_request_2.py | 77 ++++ .../models/organization_connected_account.py | 68 ++++ ...tions_upsert_client_credentials_request.py | 81 +++++ tests/fixtures/create_connected_account.json | 11 + ...create_organization_connected_account.json | 12 + ...data_integration_credentials_response.json | 8 +- .../data_integration_vended_credential.json | 17 + ...client_credentials_connection_request.json | 11 + ...ons_upsert_client_credentials_request.json | 1 - ...s_upsert_client_credentials_request_2.json | 11 + .../organization_connected_account.json | 11 + ...ons_upsert_client_credentials_request.json | 12 + tests/test_pipes.py | 120 ++++++- tests/test_pipes_models_round_trip.py | 127 ++++--- 29 files changed, 1221 insertions(+), 128 deletions(-) create mode 100644 src/workos/common/models/create_connected_account_state.py create mode 100644 src/workos/common/models/create_organization_connected_account_state.py create mode 100644 src/workos/common/models/data_integrations_create_client_credentials_connection_request_connection_owner.py create mode 100644 src/workos/common/models/data_integrations_upsert_client_credentials_request_2_connection_owner.py create mode 100644 src/workos/common/models/organization_connected_account_state.py create mode 100644 src/workos/common/models/reauthorize_data_integrations_upsert_client_credentials_request_connection_owner.py create mode 100644 src/workos/pipes/models/connected_account_input.py create mode 100644 src/workos/pipes/models/create_connected_account.py create mode 100644 src/workos/pipes/models/create_organization_connected_account.py create mode 100644 src/workos/pipes/models/data_integration_vended_credential.py create mode 100644 src/workos/pipes/models/data_integrations_create_client_credentials_connection_request.py create mode 100644 src/workos/pipes/models/data_integrations_upsert_client_credentials_request_2.py create mode 100644 src/workos/pipes/models/organization_connected_account.py create mode 100644 src/workos/pipes/models/reauthorize_data_integrations_upsert_client_credentials_request.py create mode 100644 tests/fixtures/create_connected_account.json create mode 100644 tests/fixtures/create_organization_connected_account.json create mode 100644 tests/fixtures/data_integration_vended_credential.json create mode 100644 tests/fixtures/data_integrations_create_client_credentials_connection_request.json create mode 100644 tests/fixtures/data_integrations_upsert_client_credentials_request_2.json create mode 100644 tests/fixtures/organization_connected_account.json create mode 100644 tests/fixtures/reauthorize_data_integrations_upsert_client_credentials_request.json diff --git a/src/workos/common/models/create_connected_account_state.py b/src/workos/common/models/create_connected_account_state.py new file mode 100644 index 00000000..bd11386c --- /dev/null +++ b/src/workos/common/models/create_connected_account_state.py @@ -0,0 +1,8 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .connected_account_input_state import ConnectedAccountInputState + +CreateConnectedAccountState: TypeAlias = ConnectedAccountInputState +__all__ = ["CreateConnectedAccountState"] diff --git a/src/workos/common/models/create_organization_connected_account_state.py b/src/workos/common/models/create_organization_connected_account_state.py new file mode 100644 index 00000000..1d6a8dbc --- /dev/null +++ b/src/workos/common/models/create_organization_connected_account_state.py @@ -0,0 +1,8 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .connected_account_input_state import ConnectedAccountInputState + +CreateOrganizationConnectedAccountState: TypeAlias = ConnectedAccountInputState +__all__ = ["CreateOrganizationConnectedAccountState"] diff --git a/src/workos/common/models/data_integrations_create_client_credentials_connection_request_connection_owner.py b/src/workos/common/models/data_integrations_create_client_credentials_connection_request_connection_owner.py new file mode 100644 index 00000000..5c35ec8e --- /dev/null +++ b/src/workos/common/models/data_integrations_create_client_credentials_connection_request_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner"] diff --git a/src/workos/common/models/data_integrations_upsert_client_credentials_request_2_connection_owner.py b/src/workos/common/models/data_integrations_upsert_client_credentials_request_2_connection_owner.py new file mode 100644 index 00000000..8f85d4c9 --- /dev/null +++ b/src/workos/common/models/data_integrations_upsert_client_credentials_request_2_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner"] diff --git a/src/workos/common/models/organization_connected_account_state.py b/src/workos/common/models/organization_connected_account_state.py new file mode 100644 index 00000000..effbd879 --- /dev/null +++ b/src/workos/common/models/organization_connected_account_state.py @@ -0,0 +1,8 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .connected_account_input_state import ConnectedAccountInputState + +OrganizationConnectedAccountState: TypeAlias = ConnectedAccountInputState +__all__ = ["OrganizationConnectedAccountState"] diff --git a/src/workos/common/models/reauthorize_data_integrations_upsert_client_credentials_request_connection_owner.py b/src/workos/common/models/reauthorize_data_integrations_upsert_client_credentials_request_connection_owner.py new file mode 100644 index 00000000..a54469ce --- /dev/null +++ b/src/workos/common/models/reauthorize_data_integrations_upsert_client_credentials_request_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner"] diff --git a/src/workos/pipes/_resource.py b/src/workos/pipes/_resource.py index 91a88875..b5108101 100644 --- a/src/workos/pipes/_resource.py +++ b/src/workos/pipes/_resource.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Literal if TYPE_CHECKING: from .._client import AsyncWorkOSClient, WorkOSClient @@ -11,12 +11,24 @@ from workos.common.models.connected_account_input_state import ( ConnectedAccountInputState, ) +from workos.common.models.create_connected_account_state import ( + CreateConnectedAccountState, +) from workos.common.models.create_data_integration_auth_methods import ( CreateDataIntegrationAuthMethods, ) from workos.common.models.create_data_integration_ownership import ( CreateDataIntegrationOwnership, ) +from workos.common.models.create_organization_connected_account_state import ( + CreateOrganizationConnectedAccountState, +) +from workos.common.models.data_integrations_create_api_key_connection_request_connection_owner import ( + DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner, +) +from workos.common.models.data_integrations_create_client_credentials_connection_request_connection_owner import ( + DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner, +) from workos.common.models.data_integrations_get_data_integration_authorize_url_request_connection_owner import ( DataIntegrationsGetDataIntegrationAuthorizeUrlRequestConnectionOwner, ) @@ -26,15 +38,12 @@ from workos.common.models.data_integrations_list_response import ( DataIntegrationsListResponse, ) -from workos.common.models.data_integrations_upsert_api_key_request_connection_owner import ( - DataIntegrationsUpsertApiKeyRequestConnectionOwner, -) -from workos.common.models.data_integrations_upsert_client_credentials_request_connection_owner import ( - DataIntegrationsUpsertClientCredentialsRequestConnectionOwner, -) from workos.common.models.data_integrations_vend_credentials_request_connection_owner import ( DataIntegrationsVendCredentialsRequestConnectionOwner, ) +from workos.common.models.organization_connected_account_state import ( + OrganizationConnectedAccountState, +) from workos.common.models.pagination_order import PaginationOrder from .._pagination import AsyncPage, SyncPage @@ -47,7 +56,13 @@ DataIntegrationAuthorizeUrlResponse, DataIntegrationCredentialsInput, DataIntegrationCredentialsResponse, + DataIntegrationsUpsertApiKeyRequest, + DataIntegrationsUpsertApiKeyRequest2, + DataIntegrationsUpsertClientCredentialsRequest, + DataIntegrationsUpsertClientCredentialsRequest2, PipesOwnership, + ReauthorizeDataIntegrationsUpsertApiKeyRequest, + ReauthorizeDataIntegrationsUpsertClientCredentialsRequest, UpdateCustomProviderDefinition, ) @@ -305,30 +320,30 @@ def delete_data_integration( request_options=request_options, ) - def update_data_integration_api_key( + def create_data_integration_api_key( self, slug: str, *, user_id: str, secret: str, + connection_intent: Literal["add"], organization_id: str | None = None, - connected_account_id: str | None = None, - connection_owner: DataIntegrationsUpsertApiKeyRequestConnectionOwner + connection_owner: DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner | str | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: - """Upsert an API key for a connected account + """Create another API key connected account - Creates or updates an API-key-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored API key is rotated to the new value. + Creates another API key-based connected account for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. Requires `connection_intent: add` and does not accept `connected_account_id`; use PUT to create or rotate the compatibility connection or to update an exact connection. Creating an additional connection is not yet available: until it is, this endpoint succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. Args: slug: The identifier of the integration. user_id: A [User](https://workos.com/docs/reference/authkit/user) identifier. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`. - connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection. connection_owner: Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization. secret: The API key secret to store for this integration. + connection_intent: Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -339,8 +354,6 @@ def update_data_integration_api_key( AuthenticationError: If the API key is invalid (401). AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). - ConflictError: If a conflict occurs (409). - UnprocessableEntityError: If the request data is unprocessable (422). RateLimitExceededError: If rate limited (429). ServerError: If the server returns a 5xx error. """ @@ -349,22 +362,63 @@ def update_data_integration_api_key( for k, v in { "user_id": user_id, "organization_id": organization_id, - "connected_account_id": connected_account_id, "connection_owner": enum_value(connection_owner) if connection_owner is not None else None, "secret": secret, + "connection_intent": connection_intent, }.items() if v is not None } return self._client.request( - method="put", + method="post", path=("data-integrations", str(slug), "api-key"), body=body, model=ConnectedAccount, request_options=request_options, ) + def update_data_integration_api_key( + self, + slug: str, + *, + body: DataIntegrationsUpsertApiKeyRequest + | ReauthorizeDataIntegrationsUpsertApiKeyRequest + | DataIntegrationsUpsertApiKeyRequest2 + | dict[str, Any], + request_options: RequestOptions | None = None, + ) -> ConnectedAccount: + """Upsert an API key for a connected account + + Creates or updates an API-key-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored API key is rotated to the new value. To create another connection, use POST. + + Args: + slug: The identifier of the integration. + body: The request body. Accepts: DataIntegrationsUpsertApiKeyRequest, ReauthorizeDataIntegrationsUpsertApiKeyRequest, DataIntegrationsUpsertApiKeyRequest2, or a plain dict. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + ConnectedAccount + + Raises: + BadRequestError: If the request is malformed (400). + AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). + NotFoundError: If the resource is not found (404). + ConflictError: If a conflict occurs (409). + UnprocessableEntityError: If the request data is unprocessable (422). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + _body: dict[str, Any] = body if isinstance(body, dict) else body.to_dict() + return self._client.request( + method="put", + path=("data-integrations", str(slug), "api-key"), + body=_body, + model=ConnectedAccount, + request_options=request_options, + ) + def authorize_data_integration( self, slug: str, @@ -423,34 +477,34 @@ def authorize_data_integration( request_options=request_options, ) - def update_data_integration_client_credentials( + def create_data_integration_client_credential( self, slug: str, *, user_id: str, client_id: str, client_secret: str, + connection_intent: Literal["add"], organization_id: str | None = None, - connected_account_id: str | None = None, - connection_owner: DataIntegrationsUpsertClientCredentialsRequestConnectionOwner + connection_owner: DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner | str | None = None, config: dict[str, str] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: - """Upsert client credentials for a connected account + """Create another client credentials connected account - Creates or updates a client-credentials-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored client credentials are rotated to the new values. + Creates another client credentials-based connected account for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. Requires `connection_intent: add` and does not accept `connected_account_id`; use PUT to create or rotate the compatibility connection or to update an exact connection. Creating an additional connection is not yet available: until it is, this endpoint succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. Args: slug: The identifier of the integration. user_id: A [User](https://workos.com/docs/reference/authkit/user) identifier. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`. - connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection. connection_owner: Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization. client_id: The OAuth client ID to store for this integration. client_secret: The OAuth client secret to store for this integration. config: Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors. + connection_intent: Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -461,8 +515,6 @@ def update_data_integration_client_credentials( AuthenticationError: If the API key is invalid (401). AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). - ConflictError: If a conflict occurs (409). - UnprocessableEntityError: If the request data is unprocessable (422). RateLimitExceededError: If rate limited (429). ServerError: If the server returns a 5xx error. """ @@ -471,24 +523,65 @@ def update_data_integration_client_credentials( for k, v in { "user_id": user_id, "organization_id": organization_id, - "connected_account_id": connected_account_id, "connection_owner": enum_value(connection_owner) if connection_owner is not None else None, "client_id": client_id, "client_secret": client_secret, "config": config, + "connection_intent": connection_intent, }.items() if v is not None } return self._client.request( - method="put", + method="post", path=("data-integrations", str(slug), "client-credentials"), body=body, model=ConnectedAccount, request_options=request_options, ) + def update_data_integration_client_credentials( + self, + slug: str, + *, + body: DataIntegrationsUpsertClientCredentialsRequest + | ReauthorizeDataIntegrationsUpsertClientCredentialsRequest + | DataIntegrationsUpsertClientCredentialsRequest2 + | dict[str, Any], + request_options: RequestOptions | None = None, + ) -> ConnectedAccount: + """Upsert client credentials for a connected account + + Creates or updates a client-credentials-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored client credentials are rotated to the new values. To create another connection, use POST. + + Args: + slug: The identifier of the integration. + body: The request body. Accepts: DataIntegrationsUpsertClientCredentialsRequest, ReauthorizeDataIntegrationsUpsertClientCredentialsRequest, DataIntegrationsUpsertClientCredentialsRequest2, or a plain dict. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + ConnectedAccount + + Raises: + BadRequestError: If the request is malformed (400). + AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). + NotFoundError: If the resource is not found (404). + ConflictError: If a conflict occurs (409). + UnprocessableEntityError: If the request data is unprocessable (422). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + _body: dict[str, Any] = body if isinstance(body, dict) else body.to_dict() + return self._client.request( + method="put", + path=("data-integrations", str(slug), "client-credentials"), + body=_body, + model=ConnectedAccount, + request_options=request_options, + ) + def create_data_integration_credential( self, slug: str, @@ -504,7 +597,7 @@ def create_data_integration_credential( ) -> DataIntegrationCredentialsResponse: """Vend credentials for a connected account - Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret. + Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret. Every active credential includes `config`: provider-declared, non-secret values from the installation snapshot, with current provider defaults for unset fields. Editing integration or organization configuration does not change the snapshot; reconnect or explicitly rebind the connection to adopt those edits. Defaults remain live, so a changed default can appear in `config` before a cached token is refreshed or re-minted. Credentials that never refresh require a reconnect or rebind when a default changes their routing. Args: slug: The identifier of the integration. @@ -788,16 +881,18 @@ def create_organization_connected_account( organization_id: str, slug: str, *, + user_id: str, access_token: str | None = None, refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: CreateOrganizationConnectedAccountState | str | None = None, + connection_intent: Literal["add"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Import an organization connected account - Imports an organization-owned [connected account](https://workos.com/docs/reference/pipes/connected-account) by providing OAuth tokens directly. Use this to migrate existing connections or set up connections without going through the OAuth flow. + Imports an organization-owned [connected account](https://workos.com/docs/reference/pipes/connected-account) by providing OAuth tokens directly. Omit `connection_intent` to create only the compatibility connection, or set it to `add` to explicitly create another connection. This creation-only endpoint does not accept `connected_account_id` or reauthorization intent. Args: organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. @@ -807,6 +902,8 @@ def create_organization_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. + user_id: The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization. + connection_intent: Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -814,6 +911,7 @@ def create_organization_connected_account( Raises: AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). ConflictError: If a conflict occurs (409). UnprocessableEntityError: If the request data is unprocessable (422). @@ -828,6 +926,8 @@ def create_organization_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "user_id": user_id, + "connection_intent": connection_intent, }.items() if v is not None } @@ -849,13 +949,15 @@ def update_organization_connected_account( organization_id: str, slug: str, *, + user_id: str, access_token: str | None = None, refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: OrganizationConnectedAccountState | str | None = None, supports_multiple_connections: bool | None = None, connected_account_id: str | None = None, + connection_intent: Literal["reauthorize"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Update an organization connected account @@ -870,8 +972,10 @@ def update_organization_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. - supports_multiple_connections: Set to `true` to use the plural connection contract. When omitted or `false`, only the compatibility connection is considered. + user_id: The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization. + supports_multiple_connections: Accepted for compatibility; does not change update targeting. Omit intent and selector to update the compatibility connection, or supply `connected_account_id` to update an exact connection. connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to select the connection to update. + connection_intent: Set to `reauthorize` with `connected_account_id` to update one exact connection. The intent may be omitted when supplying an ID. Omit both for permanent compatibility behavior. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -880,6 +984,7 @@ def update_organization_connected_account( Raises: BadRequestError: If the request is malformed (400). AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). ConflictError: If a conflict occurs (409). UnprocessableEntityError: If the request data is unprocessable (422). @@ -894,6 +999,7 @@ def update_organization_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "user_id": user_id, }.items() if v is not None } @@ -902,6 +1008,7 @@ def update_organization_connected_account( for k, v in { "supports_multiple_connections": supports_multiple_connections, "connected_account_id": connected_account_id, + "connection_intent": connection_intent, }.items() if v is not None } @@ -1072,7 +1179,8 @@ def create_user_connected_account( refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: CreateConnectedAccountState | str | None = None, + connection_intent: Literal["add"] | None = None, organization_id: str | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: @@ -1088,6 +1196,7 @@ def create_user_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. + connection_intent: Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. @@ -1110,6 +1219,7 @@ def create_user_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "connection_intent": connection_intent, }.items() if v is not None } @@ -1148,6 +1258,7 @@ def update_user_connected_account( organization_id: str | None = None, supports_multiple_connections: bool | None = None, connected_account_id: str | None = None, + connection_intent: Literal["reauthorize"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Update a connected account @@ -1163,8 +1274,9 @@ def update_user_connected_account( scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. - supports_multiple_connections: Set to `true` to use the plural connection contract. When omitted or `false`, only the compatibility connection is considered. + supports_multiple_connections: Accepted for compatibility; does not change update targeting. Omit intent and selector to update the compatibility connection, or supply `connected_account_id` to update an exact connection. connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to select the connection to update. + connection_intent: Set to `reauthorize` with `connected_account_id` to update one exact connection. The intent may be omitted when supplying an ID. Omit both for permanent compatibility behavior. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -1196,6 +1308,7 @@ def update_user_connected_account( "organization_id": organization_id, "supports_multiple_connections": supports_multiple_connections, "connected_account_id": connected_account_id, + "connection_intent": connection_intent, }.items() if v is not None } @@ -1563,30 +1676,30 @@ async def delete_data_integration( request_options=request_options, ) - async def update_data_integration_api_key( + async def create_data_integration_api_key( self, slug: str, *, user_id: str, secret: str, + connection_intent: Literal["add"], organization_id: str | None = None, - connected_account_id: str | None = None, - connection_owner: DataIntegrationsUpsertApiKeyRequestConnectionOwner + connection_owner: DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner | str | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: - """Upsert an API key for a connected account + """Create another API key connected account - Creates or updates an API-key-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored API key is rotated to the new value. + Creates another API key-based connected account for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. Requires `connection_intent: add` and does not accept `connected_account_id`; use PUT to create or rotate the compatibility connection or to update an exact connection. Creating an additional connection is not yet available: until it is, this endpoint succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. Args: slug: The identifier of the integration. user_id: A [User](https://workos.com/docs/reference/authkit/user) identifier. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`. - connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection. connection_owner: Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization. secret: The API key secret to store for this integration. + connection_intent: Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -1597,8 +1710,6 @@ async def update_data_integration_api_key( AuthenticationError: If the API key is invalid (401). AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). - ConflictError: If a conflict occurs (409). - UnprocessableEntityError: If the request data is unprocessable (422). RateLimitExceededError: If rate limited (429). ServerError: If the server returns a 5xx error. """ @@ -1607,22 +1718,63 @@ async def update_data_integration_api_key( for k, v in { "user_id": user_id, "organization_id": organization_id, - "connected_account_id": connected_account_id, "connection_owner": enum_value(connection_owner) if connection_owner is not None else None, "secret": secret, + "connection_intent": connection_intent, }.items() if v is not None } return await self._client.request( - method="put", + method="post", path=("data-integrations", str(slug), "api-key"), body=body, model=ConnectedAccount, request_options=request_options, ) + async def update_data_integration_api_key( + self, + slug: str, + *, + body: DataIntegrationsUpsertApiKeyRequest + | ReauthorizeDataIntegrationsUpsertApiKeyRequest + | DataIntegrationsUpsertApiKeyRequest2 + | dict[str, Any], + request_options: RequestOptions | None = None, + ) -> ConnectedAccount: + """Upsert an API key for a connected account + + Creates or updates an API-key-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored API key is rotated to the new value. To create another connection, use POST. + + Args: + slug: The identifier of the integration. + body: The request body. Accepts: DataIntegrationsUpsertApiKeyRequest, ReauthorizeDataIntegrationsUpsertApiKeyRequest, DataIntegrationsUpsertApiKeyRequest2, or a plain dict. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + ConnectedAccount + + Raises: + BadRequestError: If the request is malformed (400). + AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). + NotFoundError: If the resource is not found (404). + ConflictError: If a conflict occurs (409). + UnprocessableEntityError: If the request data is unprocessable (422). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + _body: dict[str, Any] = body if isinstance(body, dict) else body.to_dict() + return await self._client.request( + method="put", + path=("data-integrations", str(slug), "api-key"), + body=_body, + model=ConnectedAccount, + request_options=request_options, + ) + async def authorize_data_integration( self, slug: str, @@ -1681,34 +1833,34 @@ async def authorize_data_integration( request_options=request_options, ) - async def update_data_integration_client_credentials( + async def create_data_integration_client_credential( self, slug: str, *, user_id: str, client_id: str, client_secret: str, + connection_intent: Literal["add"], organization_id: str | None = None, - connected_account_id: str | None = None, - connection_owner: DataIntegrationsUpsertClientCredentialsRequestConnectionOwner + connection_owner: DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner | str | None = None, config: dict[str, str] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: - """Upsert client credentials for a connected account + """Create another client credentials connected account - Creates or updates a client-credentials-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored client credentials are rotated to the new values. + Creates another client credentials-based connected account for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. Requires `connection_intent: add` and does not accept `connected_account_id`; use PUT to create or rotate the compatibility connection or to update an exact connection. Creating an additional connection is not yet available: until it is, this endpoint succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. Args: slug: The identifier of the integration. user_id: A [User](https://workos.com/docs/reference/authkit/user) identifier. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`. - connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection. connection_owner: Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization. client_id: The OAuth client ID to store for this integration. client_secret: The OAuth client secret to store for this integration. config: Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors. + connection_intent: Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -1719,8 +1871,6 @@ async def update_data_integration_client_credentials( AuthenticationError: If the API key is invalid (401). AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). - ConflictError: If a conflict occurs (409). - UnprocessableEntityError: If the request data is unprocessable (422). RateLimitExceededError: If rate limited (429). ServerError: If the server returns a 5xx error. """ @@ -1729,24 +1879,65 @@ async def update_data_integration_client_credentials( for k, v in { "user_id": user_id, "organization_id": organization_id, - "connected_account_id": connected_account_id, "connection_owner": enum_value(connection_owner) if connection_owner is not None else None, "client_id": client_id, "client_secret": client_secret, "config": config, + "connection_intent": connection_intent, }.items() if v is not None } return await self._client.request( - method="put", + method="post", path=("data-integrations", str(slug), "client-credentials"), body=body, model=ConnectedAccount, request_options=request_options, ) + async def update_data_integration_client_credentials( + self, + slug: str, + *, + body: DataIntegrationsUpsertClientCredentialsRequest + | ReauthorizeDataIntegrationsUpsertClientCredentialsRequest + | DataIntegrationsUpsertClientCredentialsRequest2 + | dict[str, Any], + request_options: RequestOptions | None = None, + ) -> ConnectedAccount: + """Upsert client credentials for a connected account + + Creates or updates a client-credentials-based installation for the specified integration, owned by the user or, when `connection_owner` is `organization`, shared by the organization. If an installation already exists, the stored client credentials are rotated to the new values. To create another connection, use POST. + + Args: + slug: The identifier of the integration. + body: The request body. Accepts: DataIntegrationsUpsertClientCredentialsRequest, ReauthorizeDataIntegrationsUpsertClientCredentialsRequest, DataIntegrationsUpsertClientCredentialsRequest2, or a plain dict. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + ConnectedAccount + + Raises: + BadRequestError: If the request is malformed (400). + AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). + NotFoundError: If the resource is not found (404). + ConflictError: If a conflict occurs (409). + UnprocessableEntityError: If the request data is unprocessable (422). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + _body: dict[str, Any] = body if isinstance(body, dict) else body.to_dict() + return await self._client.request( + method="put", + path=("data-integrations", str(slug), "client-credentials"), + body=_body, + model=ConnectedAccount, + request_options=request_options, + ) + async def create_data_integration_credential( self, slug: str, @@ -1762,7 +1953,7 @@ async def create_data_integration_credential( ) -> DataIntegrationCredentialsResponse: """Vend credentials for a connected account - Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret. + Returns credentials for a user's connected account. Branches on the installation's `auth_method`: OAuth installations return an access token (refreshed if needed); API-key installations return the stored secret. Every active credential includes `config`: provider-declared, non-secret values from the installation snapshot, with current provider defaults for unset fields. Editing integration or organization configuration does not change the snapshot; reconnect or explicitly rebind the connection to adopt those edits. Defaults remain live, so a changed default can appear in `config` before a cached token is refreshed or re-minted. Credentials that never refresh require a reconnect or rebind when a default changes their routing. Args: slug: The identifier of the integration. @@ -2046,16 +2237,18 @@ async def create_organization_connected_account( organization_id: str, slug: str, *, + user_id: str, access_token: str | None = None, refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: CreateOrganizationConnectedAccountState | str | None = None, + connection_intent: Literal["add"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Import an organization connected account - Imports an organization-owned [connected account](https://workos.com/docs/reference/pipes/connected-account) by providing OAuth tokens directly. Use this to migrate existing connections or set up connections without going through the OAuth flow. + Imports an organization-owned [connected account](https://workos.com/docs/reference/pipes/connected-account) by providing OAuth tokens directly. Omit `connection_intent` to create only the compatibility connection, or set it to `add` to explicitly create another connection. This creation-only endpoint does not accept `connected_account_id` or reauthorization intent. Args: organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. @@ -2065,6 +2258,8 @@ async def create_organization_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. + user_id: The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization. + connection_intent: Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -2072,6 +2267,7 @@ async def create_organization_connected_account( Raises: AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). ConflictError: If a conflict occurs (409). UnprocessableEntityError: If the request data is unprocessable (422). @@ -2086,6 +2282,8 @@ async def create_organization_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "user_id": user_id, + "connection_intent": connection_intent, }.items() if v is not None } @@ -2107,13 +2305,15 @@ async def update_organization_connected_account( organization_id: str, slug: str, *, + user_id: str, access_token: str | None = None, refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: OrganizationConnectedAccountState | str | None = None, supports_multiple_connections: bool | None = None, connected_account_id: str | None = None, + connection_intent: Literal["reauthorize"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Update an organization connected account @@ -2128,8 +2328,10 @@ async def update_organization_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. - supports_multiple_connections: Set to `true` to use the plural connection contract. When omitted or `false`, only the compatibility connection is considered. + user_id: The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization. + supports_multiple_connections: Accepted for compatibility; does not change update targeting. Omit intent and selector to update the compatibility connection, or supply `connected_account_id` to update an exact connection. connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to select the connection to update. + connection_intent: Set to `reauthorize` with `connected_account_id` to update one exact connection. The intent may be omitted when supplying an ID. Omit both for permanent compatibility behavior. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -2138,6 +2340,7 @@ async def update_organization_connected_account( Raises: BadRequestError: If the request is malformed (400). AuthenticationError: If the API key is invalid (401). + AuthorizationError: If the request is forbidden (403). NotFoundError: If the resource is not found (404). ConflictError: If a conflict occurs (409). UnprocessableEntityError: If the request data is unprocessable (422). @@ -2152,6 +2355,7 @@ async def update_organization_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "user_id": user_id, }.items() if v is not None } @@ -2160,6 +2364,7 @@ async def update_organization_connected_account( for k, v in { "supports_multiple_connections": supports_multiple_connections, "connected_account_id": connected_account_id, + "connection_intent": connection_intent, }.items() if v is not None } @@ -2330,7 +2535,8 @@ async def create_user_connected_account( refresh_token: str | None = None, expires_at: str | None = None, scopes: list[str] | None = None, - state: ConnectedAccountInputState | str | None = None, + state: CreateConnectedAccountState | str | None = None, + connection_intent: Literal["add"] | None = None, organization_id: str | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: @@ -2346,6 +2552,7 @@ async def create_user_connected_account( expires_at: The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire. scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. + connection_intent: Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. @@ -2368,6 +2575,7 @@ async def create_user_connected_account( "expires_at": expires_at, "scopes": scopes, "state": enum_value(state) if state is not None else None, + "connection_intent": connection_intent, }.items() if v is not None } @@ -2406,6 +2614,7 @@ async def update_user_connected_account( organization_id: str | None = None, supports_multiple_connections: bool | None = None, connected_account_id: str | None = None, + connection_intent: Literal["reauthorize"] | None = None, request_options: RequestOptions | None = None, ) -> ConnectedAccount: """Update a connected account @@ -2421,8 +2630,9 @@ async def update_user_connected_account( scopes: The OAuth scopes granted for this connection. state: Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided. organization_id: An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. - supports_multiple_connections: Set to `true` to use the plural connection contract. When omitted or `false`, only the compatibility connection is considered. + supports_multiple_connections: Accepted for compatibility; does not change update targeting. Omit intent and selector to update the compatibility connection, or supply `connected_account_id` to update an exact connection. connected_account_id: A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to select the connection to update. + connection_intent: Set to `reauthorize` with `connected_account_id` to update one exact connection. The intent may be omitted when supplying an ID. Omit both for permanent compatibility behavior. request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. Returns: @@ -2454,6 +2664,7 @@ async def update_user_connected_account( "organization_id": organization_id, "supports_multiple_connections": supports_multiple_connections, "connected_account_id": connected_account_id, + "connection_intent": connection_intent, }.items() if v is not None } diff --git a/src/workos/pipes/models/__init__.py b/src/workos/pipes/models/__init__.py index 29ec1a35..b8842517 100644 --- a/src/workos/pipes/models/__init__.py +++ b/src/workos/pipes/models/__init__.py @@ -12,7 +12,12 @@ ) from .api_key_installation import ApiKeyInstallation as ApiKeyInstallation +from .connected_account_input import ConnectedAccountInput as ConnectedAccountInput +from .create_connected_account import CreateConnectedAccount as CreateConnectedAccount from .create_data_integration import CreateDataIntegration as CreateDataIntegration +from .create_organization_connected_account import ( + CreateOrganizationConnectedAccount as CreateOrganizationConnectedAccount, +) from .custom_provider_definition import ( CustomProviderDefinition as CustomProviderDefinition, ) @@ -42,6 +47,15 @@ from .data_integration_installation import ( DataIntegrationInstallation as DataIntegrationInstallation, ) +from .data_integration_vended_credential import ( + DataIntegrationVendedCredential as DataIntegrationVendedCredential, +) +from .data_integrations_create_api_key_connection_request import ( + DataIntegrationsCreateApiKeyConnectionRequest as DataIntegrationsCreateApiKeyConnectionRequest, +) +from .data_integrations_create_client_credentials_connection_request import ( + DataIntegrationsCreateClientCredentialsConnectionRequest as DataIntegrationsCreateClientCredentialsConnectionRequest, +) from .data_integrations_get_data_integration_authorize_url_request import ( DataIntegrationsGetDataIntegrationAuthorizeUrlRequest as DataIntegrationsGetDataIntegrationAuthorizeUrlRequest, ) @@ -51,13 +65,28 @@ from .data_integrations_upsert_api_key_request import ( DataIntegrationsUpsertApiKeyRequest as DataIntegrationsUpsertApiKeyRequest, ) +from .data_integrations_upsert_api_key_request_2 import ( + DataIntegrationsUpsertApiKeyRequest2 as DataIntegrationsUpsertApiKeyRequest2, +) from .data_integrations_upsert_client_credentials_request import ( DataIntegrationsUpsertClientCredentialsRequest as DataIntegrationsUpsertClientCredentialsRequest, ) +from .data_integrations_upsert_client_credentials_request_2 import ( + DataIntegrationsUpsertClientCredentialsRequest2 as DataIntegrationsUpsertClientCredentialsRequest2, +) from .data_integrations_vend_credentials_request import ( DataIntegrationsVendCredentialsRequest as DataIntegrationsVendCredentialsRequest, ) +from .organization_connected_account import ( + OrganizationConnectedAccount as OrganizationConnectedAccount, +) from .pipes_ownership import PipesOwnership as PipesOwnership +from .reauthorize_data_integrations_upsert_api_key_request import ( + ReauthorizeDataIntegrationsUpsertApiKeyRequest as ReauthorizeDataIntegrationsUpsertApiKeyRequest, +) +from .reauthorize_data_integrations_upsert_client_credentials_request import ( + ReauthorizeDataIntegrationsUpsertClientCredentialsRequest as ReauthorizeDataIntegrationsUpsertClientCredentialsRequest, +) from .update_custom_provider_definition import ( UpdateCustomProviderDefinition as UpdateCustomProviderDefinition, ) diff --git a/src/workos/pipes/models/connected_account_input.py b/src/workos/pipes/models/connected_account_input.py new file mode 100644 index 00000000..2bd2eb1d --- /dev/null +++ b/src/workos/pipes/models/connected_account_input.py @@ -0,0 +1,64 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import Any + +from workos._types import _format_datetime, _parse_datetime, _raise_deserialize_error +from workos.common.models.connected_account_input_state import ( + ConnectedAccountInputState, +) + + +@dataclass(slots=True) +class ConnectedAccountInput: + """Connected Account Input model.""" + + access_token: str | None = None + """The OAuth access token for the connected account.""" + refresh_token: str | None = None + """The OAuth refresh token for the connected account.""" + expires_at: datetime | None = None + """The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire.""" + scopes: list[str] | None = None + """The OAuth scopes granted for this connection.""" + state: ConnectedAccountInputState | None = None + """Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> ConnectedAccountInput: + """Deserialize from a dictionary.""" + try: + return cls( + access_token=data.get("access_token"), + refresh_token=data.get("refresh_token"), + expires_at=_parse_datetime(_v_expires_at) + if (_v_expires_at := data.get("expires_at")) is not None + else None, + scopes=data.get("scopes"), + state=ConnectedAccountInputState(_v_state) + if (_v_state := data.get("state")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("ConnectedAccountInput", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + if self.access_token is not None: + result["access_token"] = self.access_token + if self.refresh_token is not None: + result["refresh_token"] = self.refresh_token + if self.expires_at is not None: + result["expires_at"] = _format_datetime(self.expires_at) + if self.scopes is not None: + result["scopes"] = self.scopes + if self.state is not None: + result["state"] = ( + self.state.value if isinstance(self.state, Enum) else self.state + ) + return result diff --git a/src/workos/pipes/models/create_connected_account.py b/src/workos/pipes/models/create_connected_account.py new file mode 100644 index 00000000..df613a8c --- /dev/null +++ b/src/workos/pipes/models/create_connected_account.py @@ -0,0 +1,69 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import Any, Literal + +from workos._types import _format_datetime, _parse_datetime, _raise_deserialize_error +from workos.common.models.create_connected_account_state import ( + CreateConnectedAccountState, +) + + +@dataclass(slots=True) +class CreateConnectedAccount: + """Create Connected Account model.""" + + access_token: str | None = None + """The OAuth access token for the connected account.""" + refresh_token: str | None = None + """The OAuth refresh token for the connected account.""" + expires_at: datetime | None = None + """The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire.""" + scopes: list[str] | None = None + """The OAuth scopes granted for this connection.""" + state: CreateConnectedAccountState | None = None + """Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided.""" + connection_intent: Literal["add"] | None = None + """Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> CreateConnectedAccount: + """Deserialize from a dictionary.""" + try: + return cls( + access_token=data.get("access_token"), + refresh_token=data.get("refresh_token"), + expires_at=_parse_datetime(_v_expires_at) + if (_v_expires_at := data.get("expires_at")) is not None + else None, + scopes=data.get("scopes"), + state=CreateConnectedAccountState(_v_state) + if (_v_state := data.get("state")) is not None + else None, + connection_intent=data.get("connection_intent"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("CreateConnectedAccount", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + if self.access_token is not None: + result["access_token"] = self.access_token + if self.refresh_token is not None: + result["refresh_token"] = self.refresh_token + if self.expires_at is not None: + result["expires_at"] = _format_datetime(self.expires_at) + if self.scopes is not None: + result["scopes"] = self.scopes + if self.state is not None: + result["state"] = ( + self.state.value if isinstance(self.state, Enum) else self.state + ) + if self.connection_intent is not None: + result["connection_intent"] = self.connection_intent + return result diff --git a/src/workos/pipes/models/create_organization_connected_account.py b/src/workos/pipes/models/create_organization_connected_account.py new file mode 100644 index 00000000..34074f50 --- /dev/null +++ b/src/workos/pipes/models/create_organization_connected_account.py @@ -0,0 +1,73 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import Any, Literal + +from workos._types import _format_datetime, _parse_datetime, _raise_deserialize_error +from workos.common.models.create_organization_connected_account_state import ( + CreateOrganizationConnectedAccountState, +) + + +@dataclass(slots=True) +class CreateOrganizationConnectedAccount: + """Create Organization Connected Account model.""" + + user_id: str + """The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization.""" + access_token: str | None = None + """The OAuth access token for the connected account.""" + refresh_token: str | None = None + """The OAuth refresh token for the connected account.""" + expires_at: datetime | None = None + """The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire.""" + scopes: list[str] | None = None + """The OAuth scopes granted for this connection.""" + state: CreateOrganizationConnectedAccountState | None = None + """Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided.""" + connection_intent: Literal["add"] | None = None + """Set to `add` to create another connected account. Omit this field for permanent compatibility behavior. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration, which creates the compatibility connection, and otherwise returns 404 `multiple_connections_unavailable`.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> CreateOrganizationConnectedAccount: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + access_token=data.get("access_token"), + refresh_token=data.get("refresh_token"), + expires_at=_parse_datetime(_v_expires_at) + if (_v_expires_at := data.get("expires_at")) is not None + else None, + scopes=data.get("scopes"), + state=CreateOrganizationConnectedAccountState(_v_state) + if (_v_state := data.get("state")) is not None + else None, + connection_intent=data.get("connection_intent"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("CreateOrganizationConnectedAccount", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + if self.access_token is not None: + result["access_token"] = self.access_token + if self.refresh_token is not None: + result["refresh_token"] = self.refresh_token + if self.expires_at is not None: + result["expires_at"] = _format_datetime(self.expires_at) + if self.scopes is not None: + result["scopes"] = self.scopes + if self.state is not None: + result["state"] = ( + self.state.value if isinstance(self.state, Enum) else self.state + ) + if self.connection_intent is not None: + result["connection_intent"] = self.connection_intent + return result diff --git a/src/workos/pipes/models/data_integration_credentials_response.py b/src/workos/pipes/models/data_integration_credentials_response.py index 54f33d1e..a4ad02af 100644 --- a/src/workos/pipes/models/data_integration_credentials_response.py +++ b/src/workos/pipes/models/data_integration_credentials_response.py @@ -11,9 +11,7 @@ DataIntegrationCredentialsResponseError, ) -from .data_integration_credentials_response_credential import ( - DataIntegrationCredentialsResponseCredential, -) +from .data_integration_vended_credential import DataIntegrationVendedCredential @dataclass(slots=True) @@ -22,7 +20,7 @@ class DataIntegrationCredentialsResponse: active: Literal[True] | None = None """Indicates credentials are available.""" - credential: DataIntegrationCredentialsResponseCredential | None = None + credential: DataIntegrationVendedCredential | None = None """The credential object containing the vended secret.""" error: DataIntegrationCredentialsResponseError | None = None """The reason credentials are unavailable. Additional values may be added in the future; handle unknown values gracefully. @@ -35,7 +33,7 @@ def from_dict(cls, data: dict[str, Any]) -> DataIntegrationCredentialsResponse: try: return cls( active=data.get("active"), - credential=DataIntegrationCredentialsResponseCredential.from_dict( + credential=DataIntegrationVendedCredential.from_dict( cast(dict[str, Any], _v_credential) ) if (_v_credential := data.get("credential")) is not None diff --git a/src/workos/pipes/models/data_integration_vended_credential.py b/src/workos/pipes/models/data_integration_vended_credential.py new file mode 100644 index 00000000..0c93856b --- /dev/null +++ b/src/workos/pipes/models/data_integration_vended_credential.py @@ -0,0 +1,70 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Literal + +from workos._types import _raise_deserialize_error + + +@dataclass(slots=True) +class DataIntegrationVendedCredential: + """Data Integration Vended Credential model.""" + + object: Literal["credential"] | None = None + """Distinguishes the credential object.""" + auth_method: Literal["oauth"] | None = None + """The authentication method for this credential. Additional values may be added in the future; handle unknown values gracefully.""" + value: str | None = None + """The vended secret. An OAuth access token when `auth_method` is `oauth`, the API key when `api_key`, or the client-credentials access token when `client_credentials`.""" + expires_at: str | None = None + """The ISO-8601 formatted timestamp indicating when the credential expires, or `null` if it does not expire. Present for `oauth` and `client_credentials` credentials; absent for `api_key`.""" + scopes: list[str] | None = None + """The scopes granted to the access token. Present for `oauth` and `client_credentials` credentials; absent for `api_key`.""" + missing_scopes: list[str] | None = None + """If the integration has requested scopes that aren't present on the access token, they're listed here. Present for `oauth` and `client_credentials` credentials; absent for `api_key`.""" + config: dict[str, str] | None = None + """Provider-declared, non-secret config from the installation snapshot, with current defaults for unset fields. Includes both integration- and installation-scope fields; omits undeclared fields and fields marked secret. Use these values to address a per-tenant host, such as Snowflake's `account` or Zendesk's `subdomain`. Empty when no values are disclosable. Changes to integration or organization pins require reconnecting or explicitly rebinding the connection. Defaults are live and can differ from a cached token's audience until refresh or re-mint.""" + metadata: dict[str, Any] | None = None + """Non-sensitive fields captured from the provider token response (e.g. Salesforce `instance_url`), as configured for the provider. Only present for `client_credentials` credentials.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> DataIntegrationVendedCredential: + """Deserialize from a dictionary.""" + try: + return cls( + object=data.get("object"), + auth_method=data.get("auth_method"), + value=data.get("value"), + expires_at=data.get("expires_at"), + scopes=data.get("scopes"), + missing_scopes=data.get("missing_scopes"), + config=data.get("config"), + metadata=data.get("metadata"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DataIntegrationVendedCredential", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + if self.object is not None: + result["object"] = self.object + if self.auth_method is not None: + result["auth_method"] = self.auth_method + if self.value is not None: + result["value"] = self.value + if self.expires_at is not None: + result["expires_at"] = self.expires_at + else: + result["expires_at"] = None + if self.scopes is not None: + result["scopes"] = self.scopes + if self.missing_scopes is not None: + result["missing_scopes"] = self.missing_scopes + if self.config is not None: + result["config"] = self.config + if self.metadata is not None: + result["metadata"] = self.metadata + return result diff --git a/src/workos/pipes/models/data_integrations_create_client_credentials_connection_request.py b/src/workos/pipes/models/data_integrations_create_client_credentials_connection_request.py new file mode 100644 index 00000000..ac8cbc27 --- /dev/null +++ b/src/workos/pipes/models/data_integrations_create_client_credentials_connection_request.py @@ -0,0 +1,77 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any, Literal + +from workos._types import _raise_deserialize_error +from workos.common.models.data_integrations_create_client_credentials_connection_request_connection_owner import ( + DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner, +) + + +@dataclass(slots=True) +class DataIntegrationsCreateClientCredentialsConnectionRequest: + """Data Integrations Create Client Credentials Connection Request model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + client_id: str + """The OAuth client ID to store for this integration.""" + client_secret: str + """The OAuth client secret to store for this integration.""" + connection_intent: Literal["add"] + """Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: ( + DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner | None + ) = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + config: dict[str, str] | None = None + """Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> DataIntegrationsCreateClientCredentialsConnectionRequest: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + client_id=data["client_id"], + client_secret=data["client_secret"], + connection_intent=data.get("connection_intent", "add"), + organization_id=data.get("organization_id"), + connection_owner=DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + config=data.get("config"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error( + "DataIntegrationsCreateClientCredentialsConnectionRequest", e + ) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["client_id"] = self.client_id + result["client_secret"] = self.client_secret + result["connection_intent"] = self.connection_intent + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + if self.config is not None: + result["config"] = self.config + return result diff --git a/src/workos/pipes/models/data_integrations_upsert_client_credentials_request.py b/src/workos/pipes/models/data_integrations_upsert_client_credentials_request.py index 56efd7ba..1230b9e3 100644 --- a/src/workos/pipes/models/data_integrations_upsert_client_credentials_request.py +++ b/src/workos/pipes/models/data_integrations_upsert_client_credentials_request.py @@ -24,8 +24,6 @@ class DataIntegrationsUpsertClientCredentialsRequest: """The OAuth client secret to store for this integration.""" organization_id: str | None = None """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" - connected_account_id: str | None = None - """A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection.""" connection_owner: ( DataIntegrationsUpsertClientCredentialsRequestConnectionOwner | None ) = None @@ -44,7 +42,6 @@ def from_dict( client_id=data["client_id"], client_secret=data["client_secret"], organization_id=data.get("organization_id"), - connected_account_id=data.get("connected_account_id"), connection_owner=DataIntegrationsUpsertClientCredentialsRequestConnectionOwner( _v_connection_owner ) @@ -65,8 +62,6 @@ def to_dict(self) -> dict[str, Any]: result["client_secret"] = self.client_secret if self.organization_id is not None: result["organization_id"] = self.organization_id - if self.connected_account_id is not None: - result["connected_account_id"] = self.connected_account_id if self.connection_owner is not None: result["connection_owner"] = ( self.connection_owner.value diff --git a/src/workos/pipes/models/data_integrations_upsert_client_credentials_request_2.py b/src/workos/pipes/models/data_integrations_upsert_client_credentials_request_2.py new file mode 100644 index 00000000..0ccc9eb3 --- /dev/null +++ b/src/workos/pipes/models/data_integrations_upsert_client_credentials_request_2.py @@ -0,0 +1,77 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any + +from workos._types import _raise_deserialize_error +from workos.common.models.data_integrations_upsert_client_credentials_request_2_connection_owner import ( + DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner, +) + + +@dataclass(slots=True) +class DataIntegrationsUpsertClientCredentialsRequest2: + """Data Integrations Upsert Client Credentials Request2 model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + client_id: str + """The OAuth client ID to store for this integration.""" + client_secret: str + """The OAuth client secret to store for this integration.""" + connected_account_id: str + """The exact connected account to reauthorize. The reauthorize intent may be omitted for compatibility.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: ( + DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner | None + ) = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + config: dict[str, str] | None = None + """Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> DataIntegrationsUpsertClientCredentialsRequest2: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + client_id=data["client_id"], + client_secret=data["client_secret"], + connected_account_id=data["connected_account_id"], + organization_id=data.get("organization_id"), + connection_owner=DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + config=data.get("config"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error( + "DataIntegrationsUpsertClientCredentialsRequest2", e + ) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["client_id"] = self.client_id + result["client_secret"] = self.client_secret + result["connected_account_id"] = self.connected_account_id + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + if self.config is not None: + result["config"] = self.config + return result diff --git a/src/workos/pipes/models/organization_connected_account.py b/src/workos/pipes/models/organization_connected_account.py new file mode 100644 index 00000000..81e3a5bf --- /dev/null +++ b/src/workos/pipes/models/organization_connected_account.py @@ -0,0 +1,68 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import Any + +from workos._types import _format_datetime, _parse_datetime, _raise_deserialize_error +from workos.common.models.organization_connected_account_state import ( + OrganizationConnectedAccountState, +) + + +@dataclass(slots=True) +class OrganizationConnectedAccount: + """Organization Connected Account model.""" + + user_id: str + """The [User](https://workos.com/docs/reference/authkit/user) identifier of the organization member on whose behalf the connected account is being imported or updated. The user must be an active member of the organization.""" + access_token: str | None = None + """The OAuth access token for the connected account.""" + refresh_token: str | None = None + """The OAuth refresh token for the connected account.""" + expires_at: datetime | None = None + """The ISO-8601 timestamp when the access token expires. Required when `access_token` is provided for tokens that expire.""" + scopes: list[str] | None = None + """The OAuth scopes granted for this connection.""" + state: OrganizationConnectedAccountState | None = None + """Explicitly set the state of the connected account. When omitted, the state is derived from the token combination provided.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> OrganizationConnectedAccount: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + access_token=data.get("access_token"), + refresh_token=data.get("refresh_token"), + expires_at=_parse_datetime(_v_expires_at) + if (_v_expires_at := data.get("expires_at")) is not None + else None, + scopes=data.get("scopes"), + state=OrganizationConnectedAccountState(_v_state) + if (_v_state := data.get("state")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("OrganizationConnectedAccount", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + if self.access_token is not None: + result["access_token"] = self.access_token + if self.refresh_token is not None: + result["refresh_token"] = self.refresh_token + if self.expires_at is not None: + result["expires_at"] = _format_datetime(self.expires_at) + if self.scopes is not None: + result["scopes"] = self.scopes + if self.state is not None: + result["state"] = ( + self.state.value if isinstance(self.state, Enum) else self.state + ) + return result diff --git a/src/workos/pipes/models/reauthorize_data_integrations_upsert_client_credentials_request.py b/src/workos/pipes/models/reauthorize_data_integrations_upsert_client_credentials_request.py new file mode 100644 index 00000000..a5f87dbe --- /dev/null +++ b/src/workos/pipes/models/reauthorize_data_integrations_upsert_client_credentials_request.py @@ -0,0 +1,81 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any, Literal + +from workos._types import _raise_deserialize_error +from workos.common.models.reauthorize_data_integrations_upsert_client_credentials_request_connection_owner import ( + ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner, +) + + +@dataclass(slots=True) +class ReauthorizeDataIntegrationsUpsertClientCredentialsRequest: + """Reauthorize Data Integrations Upsert Client Credentials Request model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + client_id: str + """The OAuth client ID to store for this integration.""" + client_secret: str + """The OAuth client secret to store for this integration.""" + connection_intent: Literal["reauthorize"] + """Reauthorize exactly the connection named by `connected_account_id`.""" + connected_account_id: str + """The exact connected account to reauthorize. Required with `connection_intent: reauthorize`.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: ( + ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner | None + ) = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + config: dict[str, str] | None = None + """Provider-specific configuration values collected for this installation, keyed by the provider's config field descriptors.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> ReauthorizeDataIntegrationsUpsertClientCredentialsRequest: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + client_id=data["client_id"], + client_secret=data["client_secret"], + connection_intent=data.get("connection_intent", "reauthorize"), + connected_account_id=data["connected_account_id"], + organization_id=data.get("organization_id"), + connection_owner=ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + config=data.get("config"), + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error( + "ReauthorizeDataIntegrationsUpsertClientCredentialsRequest", e + ) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["client_id"] = self.client_id + result["client_secret"] = self.client_secret + result["connection_intent"] = self.connection_intent + result["connected_account_id"] = self.connected_account_id + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + if self.config is not None: + result["config"] = self.config + return result diff --git a/tests/fixtures/create_connected_account.json b/tests/fixtures/create_connected_account.json new file mode 100644 index 00000000..4b3e3862 --- /dev/null +++ b/tests/fixtures/create_connected_account.json @@ -0,0 +1,11 @@ +{ + "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "refresh_token": "ghr_xxxxxxxxxxxxxxxxxxxx", + "expires_at": "2025-12-31T23:59:59.000Z", + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "connection_intent": "add" +} diff --git a/tests/fixtures/create_organization_connected_account.json b/tests/fixtures/create_organization_connected_account.json new file mode 100644 index 00000000..41732c7a --- /dev/null +++ b/tests/fixtures/create_organization_connected_account.json @@ -0,0 +1,12 @@ +{ + "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "refresh_token": "ghr_xxxxxxxxxxxxxxxxxxxx", + "expires_at": "2025-12-31T23:59:59.000Z", + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_intent": "add" +} diff --git a/tests/fixtures/data_integration_credentials_response.json b/tests/fixtures/data_integration_credentials_response.json index 9efedd6d..bbac768e 100644 --- a/tests/fixtures/data_integration_credentials_response.json +++ b/tests/fixtures/data_integration_credentials_response.json @@ -9,7 +9,13 @@ "repo", "user:email" ], - "missing_scopes": [] + "missing_scopes": [], + "config": { + "account": "myorg-myaccount" + }, + "metadata": { + "instance_url": "https://acme.my.salesforce.com" + } }, "error": "not_installed" } diff --git a/tests/fixtures/data_integration_vended_credential.json b/tests/fixtures/data_integration_vended_credential.json new file mode 100644 index 00000000..c9958827 --- /dev/null +++ b/tests/fixtures/data_integration_vended_credential.json @@ -0,0 +1,17 @@ +{ + "object": "credential", + "auth_method": "oauth", + "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "expires_at": "2025-12-31T23:59:59.000Z", + "scopes": [ + "repo", + "user:email" + ], + "missing_scopes": [], + "config": { + "account": "myorg-myaccount" + }, + "metadata": { + "instance_url": "https://acme.my.salesforce.com" + } +} diff --git a/tests/fixtures/data_integrations_create_client_credentials_connection_request.json b/tests/fixtures/data_integrations_create_client_credentials_connection_request.json new file mode 100644 index 00000000..dc67f1b1 --- /dev/null +++ b/tests/fixtures/data_integrations_create_client_credentials_connection_request.json @@ -0,0 +1,11 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "client_id": "3MVG9...", + "client_secret": "shhh-secret", + "config": { + "salesforce_host": "acme.my.salesforce.com" + }, + "connection_intent": "add" +} diff --git a/tests/fixtures/data_integrations_upsert_client_credentials_request.json b/tests/fixtures/data_integrations_upsert_client_credentials_request.json index 9497d49c..ca9f4824 100644 --- a/tests/fixtures/data_integrations_upsert_client_credentials_request.json +++ b/tests/fixtures/data_integrations_upsert_client_credentials_request.json @@ -1,7 +1,6 @@ { "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", - "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", "connection_owner": "user", "client_id": "3MVG9...", "client_secret": "shhh-secret", diff --git a/tests/fixtures/data_integrations_upsert_client_credentials_request_2.json b/tests/fixtures/data_integrations_upsert_client_credentials_request_2.json new file mode 100644 index 00000000..6eabca26 --- /dev/null +++ b/tests/fixtures/data_integrations_upsert_client_credentials_request_2.json @@ -0,0 +1,11 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "client_id": "3MVG9...", + "client_secret": "shhh-secret", + "config": { + "salesforce_host": "acme.my.salesforce.com" + }, + "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/fixtures/organization_connected_account.json b/tests/fixtures/organization_connected_account.json new file mode 100644 index 00000000..952a4cfa --- /dev/null +++ b/tests/fixtures/organization_connected_account.json @@ -0,0 +1,11 @@ +{ + "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "refresh_token": "ghr_xxxxxxxxxxxxxxxxxxxx", + "expires_at": "2025-12-31T23:59:59.000Z", + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/fixtures/reauthorize_data_integrations_upsert_client_credentials_request.json b/tests/fixtures/reauthorize_data_integrations_upsert_client_credentials_request.json new file mode 100644 index 00000000..92465540 --- /dev/null +++ b/tests/fixtures/reauthorize_data_integrations_upsert_client_credentials_request.json @@ -0,0 +1,12 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "client_id": "3MVG9...", + "client_secret": "shhh-secret", + "config": { + "salesforce_host": "acme.my.salesforce.com" + }, + "connection_intent": "reauthorize", + "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/test_pipes.py b/tests/test_pipes.py index a4b6d3c5..d558f0f7 100644 --- a/tests/test_pipes.py +++ b/tests/test_pipes.py @@ -107,22 +107,41 @@ def test_delete_data_integration(self, workos, httpx_mock): assert request.method == "DELETE" assert request.url.path.endswith("/data-integrations/test_slug") - def test_update_data_integration_api_key(self, workos, httpx_mock): + def test_create_data_integration_api_key(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("connected_account.json"), ) - result = workos.pipes.update_data_integration_api_key( - "test_slug", user_id="test_user_id", secret="test_secret" + result = workos.pipes.create_data_integration_api_key( + "test_slug", + user_id="test_user_id", + secret="test_secret", + connection_intent="add", ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" request = httpx_mock.get_request() - assert request.method == "PUT" + assert request.method == "POST" assert request.url.path.endswith("/data-integrations/test_slug/api-key") body = json.loads(request.content) assert body["user_id"] == "test_user_id" assert body["secret"] == "test_secret" + assert body["connection_intent"] == "add" + + def test_update_data_integration_api_key(self, workos, httpx_mock): + httpx_mock.add_response( + json=load_fixture("connected_account.json"), + ) + result = workos.pipes.update_data_integration_api_key( + "test_slug", + body=load_fixture("data_integrations_upsert_api_key_request.json"), + ) + assert isinstance(result, ConnectedAccount) + assert result.object == "connected_account" + assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" + request = httpx_mock.get_request() + assert request.method == "PUT" + assert request.url.path.endswith("/data-integrations/test_slug/api-key") def test_authorize_data_integration(self, workos, httpx_mock): httpx_mock.add_response( @@ -142,21 +161,22 @@ def test_authorize_data_integration(self, workos, httpx_mock): body = json.loads(request.content) assert body["user_id"] == "test_user_id" - def test_update_data_integration_client_credentials(self, workos, httpx_mock): + def test_create_data_integration_client_credential(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("connected_account.json"), ) - result = workos.pipes.update_data_integration_client_credentials( + result = workos.pipes.create_data_integration_client_credential( "test_slug", user_id="test_user_id", client_id="test_client_id", client_secret="test_client_secret", + connection_intent="add", ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" request = httpx_mock.get_request() - assert request.method == "PUT" + assert request.method == "POST" assert request.url.path.endswith( "/data-integrations/test_slug/client-credentials" ) @@ -164,6 +184,26 @@ def test_update_data_integration_client_credentials(self, workos, httpx_mock): assert body["user_id"] == "test_user_id" assert body["client_id"] == "test_client_id" assert body["client_secret"] == "test_client_secret" + assert body["connection_intent"] == "add" + + def test_update_data_integration_client_credentials(self, workos, httpx_mock): + httpx_mock.add_response( + json=load_fixture("connected_account.json"), + ) + result = workos.pipes.update_data_integration_client_credentials( + "test_slug", + body=load_fixture( + "data_integrations_upsert_client_credentials_request.json" + ), + ) + assert isinstance(result, ConnectedAccount) + assert result.object == "connected_account" + assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" + request = httpx_mock.get_request() + assert request.method == "PUT" + assert request.url.path.endswith( + "/data-integrations/test_slug/client-credentials" + ) def test_create_data_integration_credential(self, workos, httpx_mock): httpx_mock.add_response( @@ -265,7 +305,7 @@ def test_create_organization_connected_account(self, workos, httpx_mock): json=load_fixture("connected_account.json"), ) result = workos.pipes.create_organization_connected_account( - "test_organization_id", "test_slug" + "test_organization_id", "test_slug", user_id="test_user_id" ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -275,13 +315,15 @@ def test_create_organization_connected_account(self, workos, httpx_mock): assert request.url.path.endswith( "/organizations/test_organization_id/connected_accounts/test_slug" ) + body = json.loads(request.content) + assert body["user_id"] == "test_user_id" def test_update_organization_connected_account(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("connected_account.json"), ) result = workos.pipes.update_organization_connected_account( - "test_organization_id", "test_slug" + "test_organization_id", "test_slug", user_id="test_user_id" ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -291,6 +333,8 @@ def test_update_organization_connected_account(self, workos, httpx_mock): assert request.url.path.endswith( "/organizations/test_organization_id/connected_accounts/test_slug" ) + body = json.loads(request.content) + assert body["user_id"] == "test_user_id" def test_update_organization_connected_account_encodes_query_params( self, workos, httpx_mock @@ -299,8 +343,10 @@ def test_update_organization_connected_account_encodes_query_params( workos.pipes.update_organization_connected_account( "test_organization_id", "test_slug", + user_id="test_user_id", supports_multiple_connections=True, connected_account_id="value connected_account_id/test", + connection_intent="reauthorize", ) request = httpx_mock.get_request() assert request.url.params["supports_multiple_connections"] == "true" @@ -308,6 +354,7 @@ def test_update_organization_connected_account_encodes_query_params( request.url.params["connected_account_id"] == "value connected_account_id/test" ) + assert request.url.params["connection_intent"] == "reauthorize" def test_delete_organization_connected_account(self, workos, httpx_mock): httpx_mock.add_response(status_code=204) @@ -442,6 +489,7 @@ def test_update_user_connected_account_encodes_query_params( organization_id="value organization_id/test", supports_multiple_connections=True, connected_account_id="value connected_account_id/test", + connection_intent="reauthorize", ) request = httpx_mock.get_request() assert request.url.params["organization_id"] == "value organization_id/test" @@ -450,6 +498,7 @@ def test_update_user_connected_account_encodes_query_params( request.url.params["connected_account_id"] == "value connected_account_id/test" ) + assert request.url.params["connection_intent"] == "reauthorize" def test_delete_user_connected_account(self, workos, httpx_mock): httpx_mock.add_response(status_code=204) @@ -661,11 +710,28 @@ async def test_delete_data_integration(self, async_workos, httpx_mock): assert request.method == "DELETE" assert request.url.path.endswith("/data-integrations/test_slug") + @pytest.mark.asyncio + async def test_create_data_integration_api_key(self, async_workos, httpx_mock): + httpx_mock.add_response(json=load_fixture("connected_account.json")) + result = await async_workos.pipes.create_data_integration_api_key( + "test_slug", + user_id="test_user_id", + secret="test_secret", + connection_intent="add", + ) + assert isinstance(result, ConnectedAccount) + assert result.object == "connected_account" + assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith("/data-integrations/test_slug/api-key") + @pytest.mark.asyncio async def test_update_data_integration_api_key(self, async_workos, httpx_mock): httpx_mock.add_response(json=load_fixture("connected_account.json")) result = await async_workos.pipes.update_data_integration_api_key( - "test_slug", user_id="test_user_id", secret="test_secret" + "test_slug", + body=load_fixture("data_integrations_upsert_api_key_request.json"), ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -692,15 +758,36 @@ async def test_authorize_data_integration(self, async_workos, httpx_mock): assert request.url.path.endswith("/data-integrations/test_slug/authorize") @pytest.mark.asyncio - async def test_update_data_integration_client_credentials( + async def test_create_data_integration_client_credential( self, async_workos, httpx_mock ): httpx_mock.add_response(json=load_fixture("connected_account.json")) - result = await async_workos.pipes.update_data_integration_client_credentials( + result = await async_workos.pipes.create_data_integration_client_credential( "test_slug", user_id="test_user_id", client_id="test_client_id", client_secret="test_client_secret", + connection_intent="add", + ) + assert isinstance(result, ConnectedAccount) + assert result.object == "connected_account" + assert result.id == "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith( + "/data-integrations/test_slug/client-credentials" + ) + + @pytest.mark.asyncio + async def test_update_data_integration_client_credentials( + self, async_workos, httpx_mock + ): + httpx_mock.add_response(json=load_fixture("connected_account.json")) + result = await async_workos.pipes.update_data_integration_client_credentials( + "test_slug", + body=load_fixture( + "data_integrations_upsert_client_credentials_request.json" + ), ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -817,7 +904,7 @@ async def test_create_organization_connected_account( ): httpx_mock.add_response(json=load_fixture("connected_account.json")) result = await async_workos.pipes.create_organization_connected_account( - "test_organization_id", "test_slug" + "test_organization_id", "test_slug", user_id="test_user_id" ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -834,7 +921,7 @@ async def test_update_organization_connected_account( ): httpx_mock.add_response(json=load_fixture("connected_account.json")) result = await async_workos.pipes.update_organization_connected_account( - "test_organization_id", "test_slug" + "test_organization_id", "test_slug", user_id="test_user_id" ) assert isinstance(result, ConnectedAccount) assert result.object == "connected_account" @@ -853,8 +940,10 @@ async def test_update_organization_connected_account_encodes_query_params( await async_workos.pipes.update_organization_connected_account( "test_organization_id", "test_slug", + user_id="test_user_id", supports_multiple_connections=True, connected_account_id="value connected_account_id/test", + connection_intent="reauthorize", ) request = httpx_mock.get_request() assert request.url.params["supports_multiple_connections"] == "true" @@ -862,6 +951,7 @@ async def test_update_organization_connected_account_encodes_query_params( request.url.params["connected_account_id"] == "value connected_account_id/test" ) + assert request.url.params["connection_intent"] == "reauthorize" @pytest.mark.asyncio async def test_delete_organization_connected_account( @@ -1012,6 +1102,7 @@ async def test_update_user_connected_account_encodes_query_params( organization_id="value organization_id/test", supports_multiple_connections=True, connected_account_id="value connected_account_id/test", + connection_intent="reauthorize", ) request = httpx_mock.get_request() assert request.url.params["organization_id"] == "value organization_id/test" @@ -1020,6 +1111,7 @@ async def test_update_user_connected_account_encodes_query_params( request.url.params["connected_account_id"] == "value connected_account_id/test" ) + assert request.url.params["connection_intent"] == "reauthorize" @pytest.mark.asyncio async def test_delete_user_connected_account(self, async_workos, httpx_mock): diff --git a/tests/test_pipes_models_round_trip.py b/tests/test_pipes_models_round_trip.py index 56ddf3f3..b7c5f7f4 100644 --- a/tests/test_pipes_models_round_trip.py +++ b/tests/test_pipes_models_round_trip.py @@ -20,6 +20,7 @@ DataIntegrationsListResponse, DataIntegrationsListResponseData, DataIntegrationsListResponseDataConnectedAccount, + DataIntegrationVendedCredential, UpdateCustomProviderDefinition, ) @@ -386,6 +387,48 @@ def test_data_integration_access_token_response_round_trips_unknown_enum_values( instance = DataIntegrationAccessTokenResponse.from_dict(data) assert instance.to_dict() == data + def test_data_integration_vended_credential_round_trip(self): + data = load_fixture("data_integration_vended_credential.json") + instance = DataIntegrationVendedCredential.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DataIntegrationVendedCredential.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_data_integration_vended_credential_minimal_payload(self): + data = {} + instance = DataIntegrationVendedCredential.from_dict(data) + assert instance.to_dict() is not None + + def test_data_integration_vended_credential_omits_absent_optional_non_nullable_fields( + self, + ): + data = {"expires_at": "2025-12-31T23:59:59.000Z"} + instance = DataIntegrationVendedCredential.from_dict(data) + serialized = instance.to_dict() + assert "object" not in serialized + assert "auth_method" not in serialized + assert "value" not in serialized + assert "scopes" not in serialized + assert "missing_scopes" not in serialized + assert "config" not in serialized + assert "metadata" not in serialized + + def test_data_integration_vended_credential_preserves_nullable_fields(self): + data = { + "object": "credential", + "auth_method": "oauth", + "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "expires_at": None, + "scopes": ["repo", "user:email"], + "missing_scopes": [], + "config": {"account": "myorg-myaccount"}, + "metadata": {"instance_url": "https://acme.my.salesforce.com"}, + } + instance = DataIntegrationVendedCredential.from_dict(data) + serialized = instance.to_dict() + assert serialized["expires_at"] is None + def test_data_integration_credentials_response_round_trip(self): data = load_fixture("data_integration_credentials_response.json") instance = DataIntegrationCredentialsResponse.from_dict(data) @@ -421,6 +464,8 @@ def test_data_integration_credentials_response_round_trips_unknown_enum_values( "expires_at": "2025-12-31T23:59:59.000Z", "scopes": ["repo", "user:email"], "missing_scopes": [], + "config": {"account": "myorg-myaccount"}, + "metadata": {"instance_url": "https://acme.my.salesforce.com"}, }, "error": "unexpected_data_integration_credentials_response_error", } @@ -838,47 +883,6 @@ def test_data_integrations_list_response_data_round_trips_unknown_enum_values(se instance = DataIntegrationsListResponseData.from_dict(data) assert instance.to_dict() == data - def test_data_integration_credentials_response_credential_round_trip(self): - data = load_fixture("data_integration_credentials_response_credential.json") - instance = DataIntegrationCredentialsResponseCredential.from_dict(data) - serialized = instance.to_dict() - assert serialized == data - restored = DataIntegrationCredentialsResponseCredential.from_dict(serialized) - assert restored.to_dict() == serialized - - def test_data_integration_credentials_response_credential_minimal_payload(self): - data = { - "object": "credential", - "auth_method": "oauth", - "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", - "expires_at": None, - "scopes": ["repo", "user:email"], - "missing_scopes": [], - } - instance = DataIntegrationCredentialsResponseCredential.from_dict(data) - serialized = instance.to_dict() - assert serialized["object"] == data["object"] - assert serialized["auth_method"] == data["auth_method"] - assert serialized["value"] == data["value"] - assert serialized["expires_at"] == data["expires_at"] - assert serialized["scopes"] == data["scopes"] - assert serialized["missing_scopes"] == data["missing_scopes"] - - def test_data_integration_credentials_response_credential_preserves_nullable_fields( - self, - ): - data = { - "object": "credential", - "auth_method": "oauth", - "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", - "expires_at": None, - "scopes": ["repo", "user:email"], - "missing_scopes": [], - } - instance = DataIntegrationCredentialsResponseCredential.from_dict(data) - serialized = instance.to_dict() - assert serialized["expires_at"] is None - def test_data_integration_access_token_response_access_token_round_trip(self): data = load_fixture("data_integration_access_token_response_access_token.json") instance = DataIntegrationAccessTokenResponseAccessToken.from_dict(data) @@ -1210,3 +1214,44 @@ def test_data_integrations_list_response_data_connected_account_round_trips_unkn } instance = DataIntegrationsListResponseDataConnectedAccount.from_dict(data) assert instance.to_dict() == data + + def test_data_integration_credentials_response_credential_round_trip(self): + data = load_fixture("data_integration_credentials_response_credential.json") + instance = DataIntegrationCredentialsResponseCredential.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = DataIntegrationCredentialsResponseCredential.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_data_integration_credentials_response_credential_minimal_payload(self): + data = { + "object": "credential", + "auth_method": "oauth", + "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "expires_at": None, + "scopes": ["repo", "user:email"], + "missing_scopes": [], + } + instance = DataIntegrationCredentialsResponseCredential.from_dict(data) + serialized = instance.to_dict() + assert serialized["object"] == data["object"] + assert serialized["auth_method"] == data["auth_method"] + assert serialized["value"] == data["value"] + assert serialized["expires_at"] == data["expires_at"] + assert serialized["scopes"] == data["scopes"] + assert serialized["missing_scopes"] == data["missing_scopes"] + + def test_data_integration_credentials_response_credential_preserves_nullable_fields( + self, + ): + data = { + "object": "credential", + "auth_method": "oauth", + "value": "gho_16C7e42F292c6912E7710c838347Ae178B4a", + "expires_at": None, + "scopes": ["repo", "user:email"], + "missing_scopes": [], + } + instance = DataIntegrationCredentialsResponseCredential.from_dict(data) + serialized = instance.to_dict() + assert serialized["expires_at"] is None From ec458825a2702c58593ccd9a6d64608cf35f3d5f Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:40:35 +0000 Subject: [PATCH 2/4] chore(generated): regenerate shared files for Pipes --- .last-synced-sha | 2 +- .oagen-manifest.json | 38 ++++++++++ src/workos/common/__init__.py | 25 +++++++ src/workos/common/models/__init__.py | 27 +++++++ ...key_connection_request_connection_owner.py | 10 +++ ...sert_api_key_request_2_connection_owner.py | 10 +++ ...upsert_api_key_request_connection_owner.py | 10 +++ ...tions_create_api_key_connection_request.py | 66 +++++++++++++++++ ...ata_integrations_upsert_api_key_request.py | 5 -- ...a_integrations_upsert_api_key_request_2.py | 62 ++++++++++++++++ ...ata_integrations_upsert_api_key_request.py | 72 +++++++++++++++++++ ...ons_create_api_key_connection_request.json | 7 ++ ...a_integrations_upsert_api_key_request.json | 1 - ...integrations_upsert_api_key_request_2.json | 7 ++ ...a_integrations_upsert_api_key_request.json | 8 +++ 15 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 src/workos/common/models/data_integrations_create_api_key_connection_request_connection_owner.py create mode 100644 src/workos/common/models/data_integrations_upsert_api_key_request_2_connection_owner.py create mode 100644 src/workos/common/models/reauthorize_data_integrations_upsert_api_key_request_connection_owner.py create mode 100644 src/workos/pipes/models/data_integrations_create_api_key_connection_request.py create mode 100644 src/workos/pipes/models/data_integrations_upsert_api_key_request_2.py create mode 100644 src/workos/pipes/models/reauthorize_data_integrations_upsert_api_key_request.py create mode 100644 tests/fixtures/data_integrations_create_api_key_connection_request.json create mode 100644 tests/fixtures/data_integrations_upsert_api_key_request_2.json create mode 100644 tests/fixtures/reauthorize_data_integrations_upsert_api_key_request.json diff --git a/.last-synced-sha b/.last-synced-sha index 89fbe35a..9b1ca4f2 100644 --- a/.last-synced-sha +++ b/.last-synced-sha @@ -1 +1 @@ -6f037208ce812063908f97744b4aaf4fdf570351 +e8f39fdd452f5ebca8bcdad9b8436f2bfb1d3ed7 diff --git a/.oagen-manifest.json b/.oagen-manifest.json index f04e001b..add039ed 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -281,10 +281,12 @@ "src/workos/common/models/connection_state.py", "src/workos/common/models/connection_status.py", "src/workos/common/models/connection_type.py", + "src/workos/common/models/create_connected_account_state.py", "src/workos/common/models/create_connection_oidc_options_id_token_signature_algorithm.py", "src/workos/common/models/create_connection_oidc_options_token_authentication_method.py", "src/workos/common/models/create_data_integration_auth_methods.py", "src/workos/common/models/create_data_integration_ownership.py", + "src/workos/common/models/create_organization_connected_account_state.py", "src/workos/common/models/create_user_invite_options_locale.py", "src/workos/common/models/create_user_password_hash_type.py", "src/workos/common/models/create_user_password_salt_position.py", @@ -300,6 +302,8 @@ "src/workos/common/models/data_integration_installation_connection_role.py", "src/workos/common/models/data_integration_ownership.py", "src/workos/common/models/data_integration_state.py", + "src/workos/common/models/data_integrations_create_api_key_connection_request_connection_owner.py", + "src/workos/common/models/data_integrations_create_client_credentials_connection_request_connection_owner.py", "src/workos/common/models/data_integrations_get_data_integration_authorize_url_request_connection_owner.py", "src/workos/common/models/data_integrations_get_user_token_request_connection_owner.py", "src/workos/common/models/data_integrations_list_response.py", @@ -311,7 +315,9 @@ "src/workos/common/models/data_integrations_list_response_data_connected_account_state.py", "src/workos/common/models/data_integrations_list_response_data_connection_owner.py", "src/workos/common/models/data_integrations_list_response_data_ownership.py", + "src/workos/common/models/data_integrations_upsert_api_key_request_2_connection_owner.py", "src/workos/common/models/data_integrations_upsert_api_key_request_connection_owner.py", + "src/workos/common/models/data_integrations_upsert_client_credentials_request_2_connection_owner.py", "src/workos/common/models/data_integrations_upsert_client_credentials_request_connection_owner.py", "src/workos/common/models/data_integrations_vend_credentials_request_connection_owner.py", "src/workos/common/models/directory_group.py", @@ -422,6 +428,7 @@ "src/workos/common/models/list_metadata.py", "src/workos/common/models/magic_auth_created.py", "src/workos/common/models/magic_auth_created_data.py", + "src/workos/common/models/organization_connected_account_state.py", "src/workos/common/models/organization_created.py", "src/workos/common/models/organization_created_data.py", "src/workos/common/models/organization_created_data_domain.py", @@ -516,6 +523,8 @@ "src/workos/common/models/radar_standalone_response_blocklist_type.py", "src/workos/common/models/radar_standalone_response_control.py", "src/workos/common/models/radar_standalone_response_verdict.py", + "src/workos/common/models/reauthorize_data_integrations_upsert_api_key_request_connection_owner.py", + "src/workos/common/models/reauthorize_data_integrations_upsert_client_credentials_request_connection_owner.py", "src/workos/common/models/resend_user_invite_options_locale.py", "src/workos/common/models/resource_export_completed.py", "src/workos/common/models/resource_export_completed_data.py", @@ -697,7 +706,10 @@ "src/workos/pipes/_resource.py", "src/workos/pipes/models/__init__.py", "src/workos/pipes/models/api_key_installation.py", + "src/workos/pipes/models/connected_account_input.py", + "src/workos/pipes/models/create_connected_account.py", "src/workos/pipes/models/create_data_integration.py", + "src/workos/pipes/models/create_organization_connected_account.py", "src/workos/pipes/models/custom_provider_definition.py", "src/workos/pipes/models/data_integration.py", "src/workos/pipes/models/data_integration_access_token_response.py", @@ -709,12 +721,20 @@ "src/workos/pipes/models/data_integration_credentials_response_credential.py", "src/workos/pipes/models/data_integration_custom_provider.py", "src/workos/pipes/models/data_integration_installation.py", + "src/workos/pipes/models/data_integration_vended_credential.py", + "src/workos/pipes/models/data_integrations_create_api_key_connection_request.py", + "src/workos/pipes/models/data_integrations_create_client_credentials_connection_request.py", "src/workos/pipes/models/data_integrations_get_data_integration_authorize_url_request.py", "src/workos/pipes/models/data_integrations_get_user_token_request.py", "src/workos/pipes/models/data_integrations_upsert_api_key_request.py", + "src/workos/pipes/models/data_integrations_upsert_api_key_request_2.py", "src/workos/pipes/models/data_integrations_upsert_client_credentials_request.py", + "src/workos/pipes/models/data_integrations_upsert_client_credentials_request_2.py", "src/workos/pipes/models/data_integrations_vend_credentials_request.py", + "src/workos/pipes/models/organization_connected_account.py", "src/workos/pipes/models/pipes_ownership.py", + "src/workos/pipes/models/reauthorize_data_integrations_upsert_api_key_request.py", + "src/workos/pipes/models/reauthorize_data_integrations_upsert_client_credentials_request.py", "src/workos/pipes/models/update_custom_provider_definition.py", "src/workos/pipes/models/update_data_integration.py", "src/workos/pipes_provider/__init__.py", @@ -1102,6 +1122,7 @@ "tests/fixtures/create_authkit_oauth_resource.json", "tests/fixtures/create_authorization_permission.json", "tests/fixtures/create_authorization_resource.json", + "tests/fixtures/create_connected_account.json", "tests/fixtures/create_connection.json", "tests/fixtures/create_connection_attribute_maps.json", "tests/fixtures/create_connection_key_pair.json", @@ -1121,6 +1142,7 @@ "tests/fixtures/create_oauth_application.json", "tests/fixtures/create_object_request.json", "tests/fixtures/create_organization_api_key.json", + "tests/fixtures/create_organization_connected_account.json", "tests/fixtures/create_organization_domain.json", "tests/fixtures/create_organization_role.json", "tests/fixtures/create_password_reset.json", @@ -1149,13 +1171,18 @@ "tests/fixtures/data_integration_credentials_response_credential.json", "tests/fixtures/data_integration_custom_provider.json", "tests/fixtures/data_integration_installation.json", + "tests/fixtures/data_integration_vended_credential.json", + "tests/fixtures/data_integrations_create_api_key_connection_request.json", + "tests/fixtures/data_integrations_create_client_credentials_connection_request.json", "tests/fixtures/data_integrations_get_data_integration_authorize_url_request.json", "tests/fixtures/data_integrations_get_user_token_request.json", "tests/fixtures/data_integrations_list_response.json", "tests/fixtures/data_integrations_list_response_data.json", "tests/fixtures/data_integrations_list_response_data_connected_account.json", "tests/fixtures/data_integrations_upsert_api_key_request.json", + "tests/fixtures/data_integrations_upsert_api_key_request_2.json", "tests/fixtures/data_integrations_upsert_client_credentials_request.json", + "tests/fixtures/data_integrations_upsert_client_credentials_request_2.json", "tests/fixtures/data_integrations_vend_credentials_request.json", "tests/fixtures/decrypt_request.json", "tests/fixtures/decrypt_response.json", @@ -1327,6 +1354,7 @@ "tests/fixtures/organization_api_key_with_value.json", "tests/fixtures/organization_api_key_with_value_owner.json", "tests/fixtures/organization_authorized_connect_application_list_data.json", + "tests/fixtures/organization_connected_account.json", "tests/fixtures/organization_created.json", "tests/fixtures/organization_created_data.json", "tests/fixtures/organization_created_data_domain.json", @@ -1408,6 +1436,8 @@ "tests/fixtures/radar_standalone_response.json", "tests/fixtures/radar_standalone_update_radar_attempt_request.json", "tests/fixtures/radar_standalone_update_radar_list_request.json", + "tests/fixtures/reauthorize_data_integrations_upsert_api_key_request.json", + "tests/fixtures/reauthorize_data_integrations_upsert_client_credentials_request.json", "tests/fixtures/redirect_uri.json", "tests/fixtures/redirect_uri_input.json", "tests/fixtures/refresh_token_session_authenticate_request.json", @@ -2633,6 +2663,14 @@ "GET /audit_logs/exports/{auditLogExportId}": { "sdkMethod": "get_export", "service": "audit_logs" + }, + "POST /data-integrations/{slug}/api-key": { + "sdkMethod": "create_data_integration_api_key", + "service": "pipes" + }, + "POST /data-integrations/{slug}/client-credentials": { + "sdkMethod": "create_data_integration_client_credential", + "service": "pipes" } } } diff --git a/src/workos/common/__init__.py b/src/workos/common/__init__.py index 134eadb4..0fd5abde 100644 --- a/src/workos/common/__init__.py +++ b/src/workos/common/__init__.py @@ -257,6 +257,7 @@ from .models import ConnectionState as ConnectionState from .models import ConnectionStatus as ConnectionStatus from .models import ConnectionType as ConnectionType +from .models import CreateConnectedAccountState as CreateConnectedAccountState from .models import ( CreateConnectionOIDCOptionsIdTokenSignatureAlgorithm as CreateConnectionOIDCOptionsIdTokenSignatureAlgorithm, ) @@ -265,6 +266,9 @@ ) from .models import CreateDataIntegrationAuthMethods as CreateDataIntegrationAuthMethods from .models import CreateDataIntegrationOwnership as CreateDataIntegrationOwnership +from .models import ( + CreateOrganizationConnectedAccountState as CreateOrganizationConnectedAccountState, +) from .models import CreateUserInviteOptionsLocale as CreateUserInviteOptionsLocale from .models import CreateUserPasswordHashType as CreateUserPasswordHashType from .models import CreateUserPasswordSaltPosition as CreateUserPasswordSaltPosition @@ -293,6 +297,12 @@ DataIntegrationInstallationConnectionRole as DataIntegrationInstallationConnectionRole, ) from .models import DataIntegrationOwnership as DataIntegrationOwnership +from .models import ( + DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner as DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner, +) +from .models import ( + DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner as DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner, +) from .models import ( DataIntegrationsGetDataIntegrationAuthorizeUrlRequestConnectionOwner as DataIntegrationsGetDataIntegrationAuthorizeUrlRequestConnectionOwner, ) @@ -323,9 +333,15 @@ DataIntegrationsListResponseDataOwnership as DataIntegrationsListResponseDataOwnership, ) from .models import DataIntegrationState as DataIntegrationState +from .models import ( + DataIntegrationsUpsertApiKeyRequest2ConnectionOwner as DataIntegrationsUpsertApiKeyRequest2ConnectionOwner, +) from .models import ( DataIntegrationsUpsertApiKeyRequestConnectionOwner as DataIntegrationsUpsertApiKeyRequestConnectionOwner, ) +from .models import ( + DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner as DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner, +) from .models import ( DataIntegrationsUpsertClientCredentialsRequestConnectionOwner as DataIntegrationsUpsertClientCredentialsRequestConnectionOwner, ) @@ -447,6 +463,9 @@ from .models import ListMetadata as ListMetadata from .models import MagicAuthCreated as MagicAuthCreated from .models import MagicAuthCreatedData as MagicAuthCreatedData +from .models import ( + OrganizationConnectedAccountState as OrganizationConnectedAccountState, +) from .models import OrganizationCreated as OrganizationCreated from .models import OrganizationCreatedData as OrganizationCreatedData from .models import OrganizationCreatedDataDomain as OrganizationCreatedDataDomain @@ -560,6 +579,12 @@ ) from .models import RadarStandaloneResponseControl as RadarStandaloneResponseControl from .models import RadarStandaloneResponseVerdict as RadarStandaloneResponseVerdict +from .models import ( + ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner as ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner, +) +from .models import ( + ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner as ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner, +) from .models import ResendUserInviteOptionsLocale as ResendUserInviteOptionsLocale from .models import ResourceExportCompleted as ResourceExportCompleted from .models import ResourceExportCompletedData as ResourceExportCompletedData diff --git a/src/workos/common/models/__init__.py b/src/workos/common/models/__init__.py index 9e76b7e4..8cee5ff6 100644 --- a/src/workos/common/models/__init__.py +++ b/src/workos/common/models/__init__.py @@ -427,6 +427,9 @@ from .connection_state import ConnectionState as ConnectionState from .connection_status import ConnectionStatus as ConnectionStatus from .connection_type import ConnectionType as ConnectionType +from .create_connected_account_state import ( + CreateConnectedAccountState as CreateConnectedAccountState, +) from .create_connection_oidc_options_id_token_signature_algorithm import ( CreateConnectionOIDCOptionsIdTokenSignatureAlgorithm as CreateConnectionOIDCOptionsIdTokenSignatureAlgorithm, ) @@ -439,6 +442,9 @@ from .create_data_integration_ownership import ( CreateDataIntegrationOwnership as CreateDataIntegrationOwnership, ) +from .create_organization_connected_account_state import ( + CreateOrganizationConnectedAccountState as CreateOrganizationConnectedAccountState, +) from .create_user_invite_options_locale import ( CreateUserInviteOptionsLocale as CreateUserInviteOptionsLocale, ) @@ -482,6 +488,12 @@ DataIntegrationOwnership as DataIntegrationOwnership, ) from .data_integration_state import DataIntegrationState as DataIntegrationState +from .data_integrations_create_api_key_connection_request_connection_owner import ( + DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner as DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner, +) +from .data_integrations_create_client_credentials_connection_request_connection_owner import ( + DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner as DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner, +) from .data_integrations_get_data_integration_authorize_url_request_connection_owner import ( DataIntegrationsGetDataIntegrationAuthorizeUrlRequestConnectionOwner as DataIntegrationsGetDataIntegrationAuthorizeUrlRequestConnectionOwner, ) @@ -515,9 +527,15 @@ from .data_integrations_list_response_data_ownership import ( DataIntegrationsListResponseDataOwnership as DataIntegrationsListResponseDataOwnership, ) +from .data_integrations_upsert_api_key_request_2_connection_owner import ( + DataIntegrationsUpsertApiKeyRequest2ConnectionOwner as DataIntegrationsUpsertApiKeyRequest2ConnectionOwner, +) from .data_integrations_upsert_api_key_request_connection_owner import ( DataIntegrationsUpsertApiKeyRequestConnectionOwner as DataIntegrationsUpsertApiKeyRequestConnectionOwner, ) +from .data_integrations_upsert_client_credentials_request_2_connection_owner import ( + DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner as DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner, +) from .data_integrations_upsert_client_credentials_request_connection_owner import ( DataIntegrationsUpsertClientCredentialsRequestConnectionOwner as DataIntegrationsUpsertClientCredentialsRequestConnectionOwner, ) @@ -680,6 +698,9 @@ from .list_metadata import ListMetadata as ListMetadata from .magic_auth_created import MagicAuthCreated as MagicAuthCreated from .magic_auth_created_data import MagicAuthCreatedData as MagicAuthCreatedData +from .organization_connected_account_state import ( + OrganizationConnectedAccountState as OrganizationConnectedAccountState, +) from .organization_created import OrganizationCreated as OrganizationCreated from .organization_created_data import ( OrganizationCreatedData as OrganizationCreatedData, @@ -884,6 +905,12 @@ from .radar_standalone_response_verdict import ( RadarStandaloneResponseVerdict as RadarStandaloneResponseVerdict, ) +from .reauthorize_data_integrations_upsert_api_key_request_connection_owner import ( + ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner as ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner, +) +from .reauthorize_data_integrations_upsert_client_credentials_request_connection_owner import ( + ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner as ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner, +) from .resend_user_invite_options_locale import ( ResendUserInviteOptionsLocale as ResendUserInviteOptionsLocale, ) diff --git a/src/workos/common/models/data_integrations_create_api_key_connection_request_connection_owner.py b/src/workos/common/models/data_integrations_create_api_key_connection_request_connection_owner.py new file mode 100644 index 00000000..dcdda8ec --- /dev/null +++ b/src/workos/common/models/data_integrations_create_api_key_connection_request_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner"] diff --git a/src/workos/common/models/data_integrations_upsert_api_key_request_2_connection_owner.py b/src/workos/common/models/data_integrations_upsert_api_key_request_2_connection_owner.py new file mode 100644 index 00000000..d45535dc --- /dev/null +++ b/src/workos/common/models/data_integrations_upsert_api_key_request_2_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +DataIntegrationsUpsertApiKeyRequest2ConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["DataIntegrationsUpsertApiKeyRequest2ConnectionOwner"] diff --git a/src/workos/common/models/reauthorize_data_integrations_upsert_api_key_request_connection_owner.py b/src/workos/common/models/reauthorize_data_integrations_upsert_api_key_request_connection_owner.py new file mode 100644 index 00000000..8ab90276 --- /dev/null +++ b/src/workos/common/models/reauthorize_data_integrations_upsert_api_key_request_connection_owner.py @@ -0,0 +1,10 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .create_data_integration_ownership import CreateDataIntegrationOwnership + +ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner: TypeAlias = ( + CreateDataIntegrationOwnership +) +__all__ = ["ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner"] diff --git a/src/workos/pipes/models/data_integrations_create_api_key_connection_request.py b/src/workos/pipes/models/data_integrations_create_api_key_connection_request.py new file mode 100644 index 00000000..8c6e05dd --- /dev/null +++ b/src/workos/pipes/models/data_integrations_create_api_key_connection_request.py @@ -0,0 +1,66 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any, Literal + +from workos._types import _raise_deserialize_error +from workos.common.models.data_integrations_create_api_key_connection_request_connection_owner import ( + DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner, +) + + +@dataclass(slots=True) +class DataIntegrationsCreateApiKeyConnectionRequest: + """Data Integrations Create Api Key Connection Request model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + secret: str + """The API key secret to store for this integration.""" + connection_intent: Literal["add"] + """Must be `add`: this endpoint only creates another connection. The first connection for an owner shape fills the compatibility slot; later connections are standard. Creating an additional connection is not yet available: until it is, `add` succeeds only when the owner has no connection for this integration and otherwise returns 404 `multiple_connections_unavailable`.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: ( + DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner | None + ) = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> DataIntegrationsCreateApiKeyConnectionRequest: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + secret=data["secret"], + connection_intent=data.get("connection_intent", "add"), + organization_id=data.get("organization_id"), + connection_owner=DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DataIntegrationsCreateApiKeyConnectionRequest", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["secret"] = self.secret + result["connection_intent"] = self.connection_intent + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + return result diff --git a/src/workos/pipes/models/data_integrations_upsert_api_key_request.py b/src/workos/pipes/models/data_integrations_upsert_api_key_request.py index 199f6cf8..25a6a104 100644 --- a/src/workos/pipes/models/data_integrations_upsert_api_key_request.py +++ b/src/workos/pipes/models/data_integrations_upsert_api_key_request.py @@ -22,8 +22,6 @@ class DataIntegrationsUpsertApiKeyRequest: """The API key secret to store for this integration.""" organization_id: str | None = None """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" - connected_account_id: str | None = None - """A [connected account](https://workos.com/docs/reference/pipes/connected-account) identifier. Use this to rotate a specific existing connection.""" connection_owner: DataIntegrationsUpsertApiKeyRequestConnectionOwner | None = None """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" @@ -35,7 +33,6 @@ def from_dict(cls, data: dict[str, Any]) -> DataIntegrationsUpsertApiKeyRequest: user_id=data["user_id"], secret=data["secret"], organization_id=data.get("organization_id"), - connected_account_id=data.get("connected_account_id"), connection_owner=DataIntegrationsUpsertApiKeyRequestConnectionOwner( _v_connection_owner ) @@ -52,8 +49,6 @@ def to_dict(self) -> dict[str, Any]: result["secret"] = self.secret if self.organization_id is not None: result["organization_id"] = self.organization_id - if self.connected_account_id is not None: - result["connected_account_id"] = self.connected_account_id if self.connection_owner is not None: result["connection_owner"] = ( self.connection_owner.value diff --git a/src/workos/pipes/models/data_integrations_upsert_api_key_request_2.py b/src/workos/pipes/models/data_integrations_upsert_api_key_request_2.py new file mode 100644 index 00000000..20821095 --- /dev/null +++ b/src/workos/pipes/models/data_integrations_upsert_api_key_request_2.py @@ -0,0 +1,62 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any + +from workos._types import _raise_deserialize_error +from workos.common.models.data_integrations_upsert_api_key_request_2_connection_owner import ( + DataIntegrationsUpsertApiKeyRequest2ConnectionOwner, +) + + +@dataclass(slots=True) +class DataIntegrationsUpsertApiKeyRequest2: + """Data Integrations Upsert Api Key Request2 model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + secret: str + """The API key secret to store for this integration.""" + connected_account_id: str + """The exact connected account to reauthorize. The reauthorize intent may be omitted for compatibility.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: DataIntegrationsUpsertApiKeyRequest2ConnectionOwner | None = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> DataIntegrationsUpsertApiKeyRequest2: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + secret=data["secret"], + connected_account_id=data["connected_account_id"], + organization_id=data.get("organization_id"), + connection_owner=DataIntegrationsUpsertApiKeyRequest2ConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("DataIntegrationsUpsertApiKeyRequest2", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["secret"] = self.secret + result["connected_account_id"] = self.connected_account_id + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + return result diff --git a/src/workos/pipes/models/reauthorize_data_integrations_upsert_api_key_request.py b/src/workos/pipes/models/reauthorize_data_integrations_upsert_api_key_request.py new file mode 100644 index 00000000..bf2f23c9 --- /dev/null +++ b/src/workos/pipes/models/reauthorize_data_integrations_upsert_api_key_request.py @@ -0,0 +1,72 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Any, Literal + +from workos._types import _raise_deserialize_error +from workos.common.models.reauthorize_data_integrations_upsert_api_key_request_connection_owner import ( + ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner, +) + + +@dataclass(slots=True) +class ReauthorizeDataIntegrationsUpsertApiKeyRequest: + """Reauthorize Data Integrations Upsert Api Key Request model.""" + + user_id: str + """A [User](https://workos.com/docs/reference/authkit/user) identifier.""" + secret: str + """The API key secret to store for this integration.""" + connection_intent: Literal["reauthorize"] + """Reauthorize exactly the connection named by `connected_account_id`.""" + connected_account_id: str + """The exact connected account to reauthorize. Required with `connection_intent: reauthorize`.""" + organization_id: str | None = None + """An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. Required when `connection_owner` is `organization`.""" + connection_owner: ( + ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner | None + ) = None + """Whose connection to create or rotate. `user` (the default) addresses the connection owned by `user_id`. `organization` addresses the connection shared by every member of `organization_id`; `user_id` then identifies the member performing the request and must be an active member of the organization.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> ReauthorizeDataIntegrationsUpsertApiKeyRequest: + """Deserialize from a dictionary.""" + try: + return cls( + user_id=data["user_id"], + secret=data["secret"], + connection_intent=data.get("connection_intent", "reauthorize"), + connected_account_id=data["connected_account_id"], + organization_id=data.get("organization_id"), + connection_owner=ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner( + _v_connection_owner + ) + if (_v_connection_owner := data.get("connection_owner")) is not None + else None, + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error( + "ReauthorizeDataIntegrationsUpsertApiKeyRequest", e + ) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["user_id"] = self.user_id + result["secret"] = self.secret + result["connection_intent"] = self.connection_intent + result["connected_account_id"] = self.connected_account_id + if self.organization_id is not None: + result["organization_id"] = self.organization_id + if self.connection_owner is not None: + result["connection_owner"] = ( + self.connection_owner.value + if isinstance(self.connection_owner, Enum) + else self.connection_owner + ) + return result diff --git a/tests/fixtures/data_integrations_create_api_key_connection_request.json b/tests/fixtures/data_integrations_create_api_key_connection_request.json new file mode 100644 index 00000000..18236684 --- /dev/null +++ b/tests/fixtures/data_integrations_create_api_key_connection_request.json @@ -0,0 +1,7 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "secret": "sk-1234567890abcdef", + "connection_intent": "add" +} diff --git a/tests/fixtures/data_integrations_upsert_api_key_request.json b/tests/fixtures/data_integrations_upsert_api_key_request.json index 45952523..7e72130b 100644 --- a/tests/fixtures/data_integrations_upsert_api_key_request.json +++ b/tests/fixtures/data_integrations_upsert_api_key_request.json @@ -1,7 +1,6 @@ { "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", - "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", "connection_owner": "user", "secret": "sk-1234567890abcdef" } diff --git a/tests/fixtures/data_integrations_upsert_api_key_request_2.json b/tests/fixtures/data_integrations_upsert_api_key_request_2.json new file mode 100644 index 00000000..5f088719 --- /dev/null +++ b/tests/fixtures/data_integrations_upsert_api_key_request_2.json @@ -0,0 +1,7 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "secret": "sk-1234567890abcdef", + "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/fixtures/reauthorize_data_integrations_upsert_api_key_request.json b/tests/fixtures/reauthorize_data_integrations_upsert_api_key_request.json new file mode 100644 index 00000000..186f69ab --- /dev/null +++ b/tests/fixtures/reauthorize_data_integrations_upsert_api_key_request.json @@ -0,0 +1,8 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "connection_owner": "user", + "secret": "sk-1234567890abcdef", + "connection_intent": "reauthorize", + "connected_account_id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT" +} From 110dc503346d058da1ed3bd59887e2aeb8e03b8a Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:40:43 +0000 Subject: [PATCH 3/4] chore(generated): add release notes fragment --- ...b0182d195a272be7528ca26c0ca7f936c8f789f.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md diff --git a/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md b/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md new file mode 100644 index 00000000..decb86d1 --- /dev/null +++ b/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md @@ -0,0 +1,54 @@ +* [#738](https://github.com/workos/workos-python/pull/738) feat(generated)!: regenerate from spec (1 change) + + **⚠️ Breaking** + * **[pipes](https://workos.com/docs/reference/pipes)**: + * Removed model `AddDataIntegrationsUpsertApiKeyRequest` + * Removed model `AddDataIntegrationsUpsertClientCredentialsRequest` + * Removed enum `AddDataIntegrationsUpsertApiKeyRequestConnectionOwner` + * Removed enum `AddDataIntegrationsUpsertClientCredentialsRequestConnectionOwner` + + **Features** + * **[pipes](https://workos.com/docs/reference/pipes)**: + * Added model `DataIntegrationsCreateApiKeyConnectionRequest` + * Added model `DataIntegrationsCreateClientCredentialsConnectionRequest` + * Added enum `DataIntegrationsCreateApiKeyConnectionRequestConnectionOwner` + * Added enum `DataIntegrationsCreateClientCredentialsConnectionRequestConnectionOwner` + * Added endpoint `POST /data-integrations/{slug}/api-key` + * Added endpoint `POST /data-integrations/{slug}/client-credentials` + * Added `config` to `DataIntegrationVendedCredential` + * Added model `DataIntegrationVendedCredential` + * Added model `CreateOrganizationConnectedAccount` + * Added model `CreateConnectedAccount` + * Added model `AddDataIntegrationsUpsertApiKeyRequest` + * Added model `ReauthorizeDataIntegrationsUpsertApiKeyRequest` + * Added model `DataIntegrationsUpsertApiKeyRequest2` + * Added model `AddDataIntegrationsUpsertClientCredentialsRequest` + * Added model `ReauthorizeDataIntegrationsUpsertClientCredentialsRequest` + * Added model `DataIntegrationsUpsertClientCredentialsRequest2` + * Added enum `CreateOrganizationConnectedAccountState` + * Added enum `CreateConnectedAccountState` + * Added enum `AddDataIntegrationsUpsertApiKeyRequestConnectionOwner` + * Added enum `ReauthorizeDataIntegrationsUpsertApiKeyRequestConnectionOwner` + * Added enum `DataIntegrationsUpsertApiKeyRequest2ConnectionOwner` + * Added enum `AddDataIntegrationsUpsertClientCredentialsRequestConnectionOwner` + * Added enum `ReauthorizeDataIntegrationsUpsertClientCredentialsRequestConnectionOwner` + * Added enum `DataIntegrationsUpsertClientCredentialsRequest2ConnectionOwner` + * Added parameter `OrganizationsDataProviders.updateOrganizationDataInstallation.connection_intent` + * Added parameter `UserManagementDataProviders.updateUserDataInstallation.connection_intent` + * Added model `OrganizationConnectedAccount` + * Added enum `OrganizationConnectedAccountState` + + **Fixes** + * **[pipes](https://workos.com/docs/reference/pipes)**: + * Changed request body for `Pipes.upsertApiKey` + * Changed request body for `Pipes.upsertClientCredentials` + * Changed errors for endpoint `POST /organizations/{organization_id}/connected_accounts/{slug}` + * Changed errors for endpoint `POST /user_management/users/{user_id}/connected_accounts/{slug}` + * Changed the type of `DataIntegrationCredentialsResponse.credential` + * Removed `connected_account_id` from `DataIntegrationsUpsertApiKeyRequest` + * Removed `connected_account_id` from `DataIntegrationsUpsertClientCredentialsRequest` + * Changed request body of `OrganizationsDataProviders.createOrganizationDataInstallation` from `OrganizationConnectedAccount` to `CreateOrganizationConnectedAccount` + * Changed request body of `UserManagementDataProviders.createUserDataInstallation` from `ConnectedAccountInput` to `CreateConnectedAccount` + * Changed request body of `OrganizationsDataProviders.createOrganizationDataInstallation` from `ConnectedAccountInput` to `OrganizationConnectedAccount` + * Changed request body of `OrganizationsDataProviders.updateOrganizationDataInstallation` from `ConnectedAccountInput` to `OrganizationConnectedAccount` + * Changed errors for endpoint `PUT /organizations/{organization_id}/connected_accounts/{slug}` From 24532dc38fa3263282a865dc7923545fd034abf8 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Fri, 25 Sep 2026 18:38:27 -0400 Subject: [PATCH 4/4] chore(generated): drop breaking marker from release notes fragment header --- ...6-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md b/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md index decb86d1..e7f31edd 100644 --- a/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md +++ b/.changelog-pending/2026-09-25T17-40-43-0b0182d195a272be7528ca26c0ca7f936c8f789f.md @@ -1,4 +1,4 @@ -* [#738](https://github.com/workos/workos-python/pull/738) feat(generated)!: regenerate from spec (1 change) +* [#738](https://github.com/workos/workos-python/pull/738) feat(generated): regenerate from spec (1 change) **⚠️ Breaking** * **[pipes](https://workos.com/docs/reference/pipes)**: