diff --git a/.stats.yml b/.stats.yml index 5a441b8..e4a0143 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 5 +configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openint%2Fopenint-1774a01e29ee20fa16ce371374b9a675da3d1a0a5d3cb911a4acf067d3c7351e.yml diff --git a/api.md b/api.md index b9e3ef6..949d6d2 100644 --- a/api.md +++ b/api.md @@ -5,6 +5,8 @@ Types: ```python from openint.types import ( CheckConnectionResponse, + CreateMagicLinkResponse, + CreateTokenResponse, GetConnectionResponse, ListConnectionConfigsResponse, ListConnectionsResponse, @@ -15,6 +17,8 @@ from openint.types import ( Methods: - client.check_connection(id) -> CheckConnectionResponse +- client.create_magic_link(\*\*params) -> CreateMagicLinkResponse +- client.create_token(\*\*params) -> CreateTokenResponse - client.get_connection(\*\*params) -> GetConnectionResponse - client.list_connection_configs(\*\*params) -> ListConnectionConfigsResponse - client.list_connections(id, \*\*params) -> ListConnectionsResponse diff --git a/src/openint/_client.py b/src/openint/_client.py index a466d61..71e4001 100644 --- a/src/openint/_client.py +++ b/src/openint/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, List, Union, Mapping, cast +from typing import Any, List, Union, Mapping, Optional, cast from typing_extensions import Self, Literal, override import httpx @@ -12,8 +12,10 @@ from ._qs import Querystring from .types import ( client_list_events_params, + client_create_token_params, client_get_connection_params, client_list_connections_params, + client_create_magic_link_params, client_list_connection_configs_params, ) from ._types import ( @@ -50,9 +52,11 @@ make_request_options, ) from .types.list_events_response import ListEventsResponse +from .types.create_token_response import CreateTokenResponse from .types.get_connection_response import GetConnectionResponse from .types.check_connection_response import CheckConnectionResponse from .types.list_connections_response import ListConnectionsResponse +from .types.create_magic_link_response import CreateMagicLinkResponse from .types.list_connection_configs_response import ListConnectionConfigsResponse __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Openint", "AsyncOpenint", "Client", "AsyncClient"] @@ -238,6 +242,170 @@ def check_connection( cast_to=CheckConnectionResponse, ) + def create_magic_link( + self, + *, + customer_id: str, + email: str, + connection_id: Optional[str] | NotGiven = NOT_GIVEN, + connector_names: Optional[ + Literal[ + "aircall", + "airtable", + "apollo", + "beancount", + "brex", + "coda", + "confluence", + "debug", + "discord", + "finch", + "firebase", + "foreceipt", + "fs", + "github", + "gong", + "google", + "greenhouse", + "heron", + "hubspot", + "intercom", + "jira", + "kustomer", + "lever", + "linear", + "lunchmoney", + "merge", + "microsoft", + "mongodb", + "moota", + "onebrick", + "outreach", + "pipedrive", + "plaid", + "postgres", + "qbo", + "ramp", + "revert", + "salesforce", + "salesloft", + "saltedge", + "slack", + "splitwise", + "spreadsheet", + "stripe", + "teller", + "toggl", + "twenty", + "webhook", + "wise", + "xero", + "yodlee", + "zohodesk", + "googledrive", + ] + ] + | NotGiven = NOT_GIVEN, + redirect_url: Optional[str] | NotGiven = NOT_GIVEN, + theme: Optional[Literal["light", "dark"]] | NotGiven = NOT_GIVEN, + validity_in_seconds: float | NotGiven = NOT_GIVEN, + view: Optional[Literal["manage", "manage-deeplink", "add", "add-deeplink"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> CreateMagicLinkResponse: + """ + Create a magic link for connecting integrations + + Args: + email: The email address of the customer + + connector_names: Filter integrations by comma separated connector names + + redirect_url: Where to send user to after connect / if they press back button + + theme: Magic Link display theme + + validity_in_seconds: How long the magic link will be valid for (in seconds) before it expires + + view: Magic Link tab view + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self.post( + "/connect/magic-link", + body=maybe_transform( + { + "customer_id": customer_id, + "email": email, + "connection_id": connection_id, + "connector_names": connector_names, + "redirect_url": redirect_url, + "theme": theme, + "validity_in_seconds": validity_in_seconds, + "view": view, + }, + client_create_magic_link_params.ClientCreateMagicLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreateMagicLinkResponse, + ) + + def create_token( + self, + *, + customer_id: str, + validity_in_seconds: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> CreateTokenResponse: + """ + Create an authentication token for a customer + + Args: + customer_id: Anything that uniquely identifies the customer that you will be sending the + token to + + validity_in_seconds: How long the token will be valid for (in seconds) before it expires + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self.post( + "/connect/token", + body=maybe_transform( + { + "customer_id": customer_id, + "validity_in_seconds": validity_in_seconds, + }, + client_create_token_params.ClientCreateTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreateTokenResponse, + ) + def get_connection( self, *, @@ -765,6 +933,170 @@ async def check_connection( cast_to=CheckConnectionResponse, ) + async def create_magic_link( + self, + *, + customer_id: str, + email: str, + connection_id: Optional[str] | NotGiven = NOT_GIVEN, + connector_names: Optional[ + Literal[ + "aircall", + "airtable", + "apollo", + "beancount", + "brex", + "coda", + "confluence", + "debug", + "discord", + "finch", + "firebase", + "foreceipt", + "fs", + "github", + "gong", + "google", + "greenhouse", + "heron", + "hubspot", + "intercom", + "jira", + "kustomer", + "lever", + "linear", + "lunchmoney", + "merge", + "microsoft", + "mongodb", + "moota", + "onebrick", + "outreach", + "pipedrive", + "plaid", + "postgres", + "qbo", + "ramp", + "revert", + "salesforce", + "salesloft", + "saltedge", + "slack", + "splitwise", + "spreadsheet", + "stripe", + "teller", + "toggl", + "twenty", + "webhook", + "wise", + "xero", + "yodlee", + "zohodesk", + "googledrive", + ] + ] + | NotGiven = NOT_GIVEN, + redirect_url: Optional[str] | NotGiven = NOT_GIVEN, + theme: Optional[Literal["light", "dark"]] | NotGiven = NOT_GIVEN, + validity_in_seconds: float | NotGiven = NOT_GIVEN, + view: Optional[Literal["manage", "manage-deeplink", "add", "add-deeplink"]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> CreateMagicLinkResponse: + """ + Create a magic link for connecting integrations + + Args: + email: The email address of the customer + + connector_names: Filter integrations by comma separated connector names + + redirect_url: Where to send user to after connect / if they press back button + + theme: Magic Link display theme + + validity_in_seconds: How long the magic link will be valid for (in seconds) before it expires + + view: Magic Link tab view + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self.post( + "/connect/magic-link", + body=await async_maybe_transform( + { + "customer_id": customer_id, + "email": email, + "connection_id": connection_id, + "connector_names": connector_names, + "redirect_url": redirect_url, + "theme": theme, + "validity_in_seconds": validity_in_seconds, + "view": view, + }, + client_create_magic_link_params.ClientCreateMagicLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreateMagicLinkResponse, + ) + + async def create_token( + self, + *, + customer_id: str, + validity_in_seconds: float | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> CreateTokenResponse: + """ + Create an authentication token for a customer + + Args: + customer_id: Anything that uniquely identifies the customer that you will be sending the + token to + + validity_in_seconds: How long the token will be valid for (in seconds) before it expires + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self.post( + "/connect/token", + body=await async_maybe_transform( + { + "customer_id": customer_id, + "validity_in_seconds": validity_in_seconds, + }, + client_create_token_params.ClientCreateTokenParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreateTokenResponse, + ) + async def get_connection( self, *, @@ -1117,6 +1449,12 @@ def __init__(self, client: Openint) -> None: self.check_connection = to_raw_response_wrapper( client.check_connection, ) + self.create_magic_link = to_raw_response_wrapper( + client.create_magic_link, + ) + self.create_token = to_raw_response_wrapper( + client.create_token, + ) self.get_connection = to_raw_response_wrapper( client.get_connection, ) @@ -1136,6 +1474,12 @@ def __init__(self, client: AsyncOpenint) -> None: self.check_connection = async_to_raw_response_wrapper( client.check_connection, ) + self.create_magic_link = async_to_raw_response_wrapper( + client.create_magic_link, + ) + self.create_token = async_to_raw_response_wrapper( + client.create_token, + ) self.get_connection = async_to_raw_response_wrapper( client.get_connection, ) @@ -1155,6 +1499,12 @@ def __init__(self, client: Openint) -> None: self.check_connection = to_streamed_response_wrapper( client.check_connection, ) + self.create_magic_link = to_streamed_response_wrapper( + client.create_magic_link, + ) + self.create_token = to_streamed_response_wrapper( + client.create_token, + ) self.get_connection = to_streamed_response_wrapper( client.get_connection, ) @@ -1174,6 +1524,12 @@ def __init__(self, client: AsyncOpenint) -> None: self.check_connection = async_to_streamed_response_wrapper( client.check_connection, ) + self.create_magic_link = async_to_streamed_response_wrapper( + client.create_magic_link, + ) + self.create_token = async_to_streamed_response_wrapper( + client.create_token, + ) self.get_connection = async_to_streamed_response_wrapper( client.get_connection, ) diff --git a/src/openint/types/__init__.py b/src/openint/types/__init__.py index 73a1db8..9c39d0e 100644 --- a/src/openint/types/__init__.py +++ b/src/openint/types/__init__.py @@ -3,12 +3,16 @@ from __future__ import annotations from .list_events_response import ListEventsResponse as ListEventsResponse +from .create_token_response import CreateTokenResponse as CreateTokenResponse from .get_connection_response import GetConnectionResponse as GetConnectionResponse from .check_connection_response import CheckConnectionResponse as CheckConnectionResponse from .client_list_events_params import ClientListEventsParams as ClientListEventsParams from .list_connections_response import ListConnectionsResponse as ListConnectionsResponse +from .client_create_token_params import ClientCreateTokenParams as ClientCreateTokenParams +from .create_magic_link_response import CreateMagicLinkResponse as CreateMagicLinkResponse from .client_get_connection_params import ClientGetConnectionParams as ClientGetConnectionParams from .client_list_connections_params import ClientListConnectionsParams as ClientListConnectionsParams +from .client_create_magic_link_params import ClientCreateMagicLinkParams as ClientCreateMagicLinkParams from .list_connection_configs_response import ListConnectionConfigsResponse as ListConnectionConfigsResponse from .client_list_connection_configs_params import ( ClientListConnectionConfigsParams as ClientListConnectionConfigsParams, diff --git a/src/openint/types/client_create_magic_link_params.py b/src/openint/types/client_create_magic_link_params.py new file mode 100644 index 0000000..9989433 --- /dev/null +++ b/src/openint/types/client_create_magic_link_params.py @@ -0,0 +1,88 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ClientCreateMagicLinkParams"] + + +class ClientCreateMagicLinkParams(TypedDict, total=False): + customer_id: Required[str] + + email: Required[str] + """The email address of the customer""" + + connection_id: Optional[str] + + connector_names: Optional[ + Literal[ + "aircall", + "airtable", + "apollo", + "beancount", + "brex", + "coda", + "confluence", + "debug", + "discord", + "finch", + "firebase", + "foreceipt", + "fs", + "github", + "gong", + "google", + "greenhouse", + "heron", + "hubspot", + "intercom", + "jira", + "kustomer", + "lever", + "linear", + "lunchmoney", + "merge", + "microsoft", + "mongodb", + "moota", + "onebrick", + "outreach", + "pipedrive", + "plaid", + "postgres", + "qbo", + "ramp", + "revert", + "salesforce", + "salesloft", + "saltedge", + "slack", + "splitwise", + "spreadsheet", + "stripe", + "teller", + "toggl", + "twenty", + "webhook", + "wise", + "xero", + "yodlee", + "zohodesk", + "googledrive", + ] + ] + """Filter integrations by comma separated connector names""" + + redirect_url: Optional[str] + """Where to send user to after connect / if they press back button""" + + theme: Optional[Literal["light", "dark"]] + """Magic Link display theme""" + + validity_in_seconds: float + """How long the magic link will be valid for (in seconds) before it expires""" + + view: Optional[Literal["manage", "manage-deeplink", "add", "add-deeplink"]] + """Magic Link tab view""" diff --git a/src/openint/types/client_create_token_params.py b/src/openint/types/client_create_token_params.py new file mode 100644 index 0000000..821f434 --- /dev/null +++ b/src/openint/types/client_create_token_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ClientCreateTokenParams"] + + +class ClientCreateTokenParams(TypedDict, total=False): + customer_id: Required[str] + """ + Anything that uniquely identifies the customer that you will be sending the + token to + """ + + validity_in_seconds: float + """How long the token will be valid for (in seconds) before it expires""" diff --git a/src/openint/types/create_magic_link_response.py b/src/openint/types/create_magic_link_response.py new file mode 100644 index 0000000..ace38fa --- /dev/null +++ b/src/openint/types/create_magic_link_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from .._models import BaseModel + +__all__ = ["CreateMagicLinkResponse"] + + +class CreateMagicLinkResponse(BaseModel): + url: str diff --git a/src/openint/types/create_token_response.py b/src/openint/types/create_token_response.py new file mode 100644 index 0000000..dc0b804 --- /dev/null +++ b/src/openint/types/create_token_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + + +from .._models import BaseModel + +__all__ = ["CreateTokenResponse"] + + +class CreateTokenResponse(BaseModel): + token: str diff --git a/tests/api_resources/test_client.py b/tests/api_resources/test_client.py index 0f4a187..02e3154 100644 --- a/tests/api_resources/test_client.py +++ b/tests/api_resources/test_client.py @@ -11,8 +11,10 @@ from tests.utils import assert_matches_type from openint.types import ( ListEventsResponse, + CreateTokenResponse, GetConnectionResponse, CheckConnectionResponse, + CreateMagicLinkResponse, ListConnectionsResponse, ListConnectionConfigsResponse, ) @@ -65,6 +67,101 @@ def test_path_params_check_connection(self, client: Openint) -> None: "", ) + @pytest.mark.skip() + @parametrize + def test_method_create_magic_link(self, client: Openint) -> None: + client_ = client.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) + assert_matches_type(CreateMagicLinkResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_magic_link_with_all_params(self, client: Openint) -> None: + client_ = client.create_magic_link( + customer_id="x", + email="dev@stainless.com", + connection_id="connection_id", + connector_names="aircall", + redirect_url="redirect_url", + theme="light", + validity_in_seconds=0, + view="manage", + ) + assert_matches_type(CreateMagicLinkResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_magic_link(self, client: Openint) -> None: + response = client.with_raw_response.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client_ = response.parse() + assert_matches_type(CreateMagicLinkResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_magic_link(self, client: Openint) -> None: + with client.with_streaming_response.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client_ = response.parse() + assert_matches_type(CreateMagicLinkResponse, client_, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_create_token(self, client: Openint) -> None: + client_ = client.create_token( + customer_id="x", + ) + assert_matches_type(CreateTokenResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_token_with_all_params(self, client: Openint) -> None: + client_ = client.create_token( + customer_id="x", + validity_in_seconds=1, + ) + assert_matches_type(CreateTokenResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create_token(self, client: Openint) -> None: + response = client.with_raw_response.create_token( + customer_id="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client_ = response.parse() + assert_matches_type(CreateTokenResponse, client_, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create_token(self, client: Openint) -> None: + with client.with_streaming_response.create_token( + customer_id="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client_ = response.parse() + assert_matches_type(CreateTokenResponse, client_, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip() @parametrize def test_method_get_connection(self, client: Openint) -> None: @@ -282,6 +379,101 @@ async def test_path_params_check_connection(self, async_client: AsyncOpenint) -> "", ) + @pytest.mark.skip() + @parametrize + async def test_method_create_magic_link(self, async_client: AsyncOpenint) -> None: + client = await async_client.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) + assert_matches_type(CreateMagicLinkResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_magic_link_with_all_params(self, async_client: AsyncOpenint) -> None: + client = await async_client.create_magic_link( + customer_id="x", + email="dev@stainless.com", + connection_id="connection_id", + connector_names="aircall", + redirect_url="redirect_url", + theme="light", + validity_in_seconds=0, + view="manage", + ) + assert_matches_type(CreateMagicLinkResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_magic_link(self, async_client: AsyncOpenint) -> None: + response = await async_client.with_raw_response.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client = await response.parse() + assert_matches_type(CreateMagicLinkResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_magic_link(self, async_client: AsyncOpenint) -> None: + async with async_client.with_streaming_response.create_magic_link( + customer_id="x", + email="dev@stainless.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client = await response.parse() + assert_matches_type(CreateMagicLinkResponse, client, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_create_token(self, async_client: AsyncOpenint) -> None: + client = await async_client.create_token( + customer_id="x", + ) + assert_matches_type(CreateTokenResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_token_with_all_params(self, async_client: AsyncOpenint) -> None: + client = await async_client.create_token( + customer_id="x", + validity_in_seconds=1, + ) + assert_matches_type(CreateTokenResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create_token(self, async_client: AsyncOpenint) -> None: + response = await async_client.with_raw_response.create_token( + customer_id="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + client = await response.parse() + assert_matches_type(CreateTokenResponse, client, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create_token(self, async_client: AsyncOpenint) -> None: + async with async_client.with_streaming_response.create_token( + customer_id="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + client = await response.parse() + assert_matches_type(CreateTokenResponse, client, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip() @parametrize async def test_method_get_connection(self, async_client: AsyncOpenint) -> None: