From f430fdd3e576a26e0cea166b338c970ded593a8b Mon Sep 17 00:00:00 2001 From: Manuel Alejandro Paz Cetina Date: Sun, 19 Oct 2025 03:02:30 -0600 Subject: [PATCH 1/5] update endpoint paths and response types - Update response types for various endpoints - Add new endpoints for user identities management --- kinde_sdk/management/management_client.py | 92 +++++++++++------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 96a50ab4..bea66d19 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -37,10 +37,10 @@ class ManagementClient: # Organizations API 'organizations': { 'list': ('GET', '/api/v1/organizations'), - 'get': ('GET', '/api/v1/organizations/{org_code}'), + 'get': ('GET', '/api/v1/organization/{org_code}'), 'create': ('POST', '/api/v1/organization'), - 'update': ('PATCH', '/api/v1/organizations/{org_code}'), - 'delete': ('DELETE', '/api/v1/organizations/{org_code}'), + 'update': ('PATCH', '/api/v1/organization/{org_code}'), + 'delete': ('DELETE', '/api/v1/organization/{org_code}'), }, # Organization Users API @@ -69,7 +69,7 @@ class ManagementClient: 'roles': { 'list': ('GET', '/api/v1/roles'), 'get': ('GET', '/api/v1/roles/{role_id}'), - 'create': ('POST', '/api/v1/role'), + 'create': ('POST', '/api/v1/roles'), 'update': ('PATCH', '/api/v1/roles/{role_id}'), 'delete': ('DELETE', '/api/v1/roles/{role_id}'), }, @@ -77,18 +77,15 @@ class ManagementClient: # Permissions API 'permissions': { 'list': ('GET', '/api/v1/permissions'), - 'get': ('GET', '/api/v1/permissions/{permission_id}'), - 'create': ('POST', '/api/v1/permission'), + 'create': ('POST', '/api/v1/permissions'), 'update': ('PATCH', '/api/v1/permissions/{permission_id}'), 'delete': ('DELETE', '/api/v1/permissions/{permission_id}'), }, # Feature Flags API 'feature_flags': { - 'list': ('GET', '/api/v1/feature_flags'), - 'get': ('GET', '/api/v1/feature_flags/{feature_flag_key}'), - 'create': ('POST', '/api/v1/feature_flag'), - 'update': ('PATCH', '/api/v1/feature_flags/{feature_flag_key}'), + 'create': ('POST', '/api/v1/feature_flags'), + 'update': ('PUT', '/api/v1/feature_flags/{feature_flag_key}'), 'delete': ('DELETE', '/api/v1/feature_flags/{feature_flag_key}'), }, @@ -96,7 +93,7 @@ class ManagementClient: 'connected_apps': { 'list': ('GET', '/api/v1/applications'), 'get': ('GET', '/api/v1/applications/{application_id}'), - 'create': ('POST', '/api/v1/application'), + 'create': ('POST', '/api/v1/applications'), 'update': ('PATCH', '/api/v1/applications/{application_id}'), 'delete': ('DELETE', '/api/v1/applications/{application_id}'), }, @@ -105,8 +102,7 @@ class ManagementClient: 'api_applications': { 'list': ('GET', '/api/v1/apis'), 'get': ('GET', '/api/v1/apis/{api_id}'), - 'create': ('POST', '/api/v1/api'), - 'update': ('PATCH', '/api/v1/apis/{api_id}'), + 'create': ('POST', '/api/v1/apis'), 'delete': ('DELETE', '/api/v1/apis/{api_id}'), }, @@ -114,6 +110,7 @@ class ManagementClient: 'subscribers': { 'list': ('GET', '/api/v1/subscribers'), 'get': ('GET', '/api/v1/subscribers/{subscriber_id}'), + 'create': ('POST', '/api/v1/subscribers'), }, # Timezones API @@ -129,30 +126,26 @@ class ManagementClient: # Properties API 'properties': { 'list': ('GET', '/api/v1/properties'), - 'get': ('GET', '/api/v1/properties/{property_id}'), 'create': ('POST', '/api/v1/properties'), - 'update': ('PATCH', '/api/v1/properties/{property_id}'), + 'update': ('PUT', '/api/v1/properties/{property_id}'), 'delete': ('DELETE', '/api/v1/properties/{property_id}'), }, # User Properties API 'user_properties': { 'list': ('GET', '/api/v1/users/{user_id}/properties'), - 'get': ('GET', '/api/v1/users/{user_id}/properties/{property_key}'), 'update': ('PUT', '/api/v1/users/{user_id}/properties/{property_key}'), }, # Organization Properties API 'organization_properties': { 'list': ('GET', '/api/v1/organizations/{org_code}/properties'), - 'get': ('GET', '/api/v1/organizations/{org_code}/properties/{property_key}'), 'update': ('PUT', '/api/v1/organizations/{org_code}/properties/{property_key}'), }, # Webhooks API 'webhooks': { 'list': ('GET', '/api/v1/webhooks'), - 'get': ('GET', '/api/v1/webhooks/{webhook_id}'), 'create': ('POST', '/api/v1/webhooks'), 'update': ('PATCH', '/api/v1/webhooks/{webhook_id}'), 'delete': ('DELETE', '/api/v1/webhooks/{webhook_id}'), @@ -180,12 +173,12 @@ class ManagementClient: # Business API 'business': { 'get': ('GET', '/api/v1/business'), + 'update': ('PATCH', '/api/v1/business'), }, # Environment Feature Flags API 'environment_feature_flags': { 'list': ('GET', '/api/v1/environment/feature_flags'), - 'get': ('GET', '/api/v1/environment/feature_flags/{feature_flag_key}'), 'update': ('PATCH', '/api/v1/environment/feature_flags/{feature_flag_key}'), 'delete': ('DELETE', '/api/v1/environment/feature_flags/{feature_flag_key}'), }, @@ -193,14 +186,12 @@ class ManagementClient: # Organization Feature Flags API 'organization_feature_flags': { 'list': ('GET', '/api/v1/organizations/{org_code}/feature_flags'), - 'get': ('GET', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'), 'update': ('PATCH', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'), 'delete': ('DELETE', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'), }, # User Feature Flags API 'user_feature_flags': { - 'get': ('GET', '/api/v1/users/{user_id}/feature_flags/{feature_flag_key}'), 'update': ('PATCH', '/api/v1/users/{user_id}/feature_flags/{feature_flag_key}'), }, @@ -213,6 +204,15 @@ class ManagementClient: 'user_refresh_claims': { 'refresh': ('POST', '/api/v1/users/{user_id}/refresh_claims'), }, + 'user_identities': { + 'list': ('GET', '/api/v1/users/{user_id}/identities'), + 'create': ('POST', '/api/v1/users/{user_id}/identities'), + }, + 'identities': { + 'get': ('GET', '/api/v1/identities/{identity_id}'), + 'update': ('PATCH', '/api/v1/identities/{identity_id}'), + 'delete': ('DELETE', '/api/v1/identities/{identity_id}'), + }, } # Define response types for each endpoint @@ -220,50 +220,47 @@ class ManagementClient: 'users': { 'list': {'200': 'UsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'User', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'201': 'CreateUserResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'200': 'CreateUserResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'UpdateUserResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organizations': { 'list': {'200': 'GetOrganizationsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'201': 'CreateOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'200': 'CreateOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organization_users': { 'list': {'200': 'GetOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'add': {'201': 'AddOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'add': {'200': 'AddOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'UpdateOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organization_user_roles': { 'list': {'200': 'GetOrganizationsUserRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'add': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'add': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organization_user_permissions': { 'list': {'200': 'GetOrganizationsUserPermissionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'add': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'add': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'roles': { 'list': {'200': 'GetRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetRoleResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'201': 'CreateRoleResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'update': {'200': 'UpdateRoleResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'201': 'CreateRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'update': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'permissions': { 'list': {'200': 'GetPermissionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'Permissions', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'feature_flags': { - 'list': {'200': 'GetFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetFeatureFlagsResponseDataFeatureFlagsInner', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, @@ -271,19 +268,19 @@ class ManagementClient: 'subscribers': { 'list': {'200': 'GetSubscribersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetSubscriberResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'201': 'CreateSubscriberSuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'api_applications': { 'list': {'200': 'GetApisResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetApiResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'201': 'CreateApiResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'update': {'200': 'UpdateApiResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'200': 'CreateApisResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'connected_apps': { 'list': {'200': 'GetApplicationsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetApplicationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'CreateApplicationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'update': {'200': 'UpdateApplicationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'timezones': { @@ -294,26 +291,22 @@ class ManagementClient: }, 'properties': { 'list': {'200': 'GetPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'CreatePropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'user_properties': { - 'list': {'200': 'GetUserPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetUserPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'list': {'200': 'GetPropertyValuesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organization_properties': { - 'list': {'200': 'GetOrganizationPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetOrganizationPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'list': {'200': 'GetPropertyValuesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'webhooks': { 'list': {'200': 'GetWebhooksResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'201': 'CreateWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'200': 'CreateWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'update': {'200': 'UpdateWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'events': { @@ -324,28 +317,26 @@ class ManagementClient: }, 'connections': { 'list': {'200': 'GetConnectionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'get': {'200': 'Connection', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'CreateConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'business': { 'get': {'200': 'GetBusinessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'environment_feature_flags': { 'list': {'200': 'GetEnvironmentFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetEnvironmentFeatureFlagsResponseDataFeatureFlagsInner', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'organization_feature_flags': { 'list': {'200': 'GetOrganizationFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'GetOrganizationFeatureFlagsResponseDataFeatureFlagsInner', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'user_feature_flags': { - 'get': {'200': 'GetUserFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'user_password': { @@ -354,6 +345,15 @@ class ManagementClient: 'user_refresh_claims': { 'refresh': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, + 'user_identities': { + 'list': {'200': 'GetIdentitiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'201': 'CreateIdentityResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + }, + 'identities': { + 'get': {'200': 'Identity', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + }, } def __init__(self, domain: str, client_id: str, client_secret: str): From 56d744f0db8e7ca185f5a575be1c160557b91249 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Wed, 26 Nov 2025 19:30:40 +0200 Subject: [PATCH 2/5] fix: correct singularization for user_identities and identities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the singularization bug that was generating incorrect method names: - create_user_identitie → create_user_identity - get_identitie → get_identity - update_identitie → update_identity - delete_identitie → delete_identity Changes: - Add _singularize_resource() helper method to centralize singularization logic - Handle special cases: user_identities → user_identity, identities → identity - Update both _generate_methods() and _create_api_method() to use the helper - Maintains existing behavior for other resources (users, organizations, etc.) This fixes a pre-existing bug that was exposed by PR #128's addition of user_identities and identities endpoints. --- kinde_sdk/management/management_client.py | 35 ++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index bea66d19..60ad55ba 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -384,14 +384,33 @@ def _setup_token_handling(self): # Token will be added directly in the API method since we're calling REST client directly pass + def _singularize_resource(self, resource: str) -> str: + """ + Convert a plural resource name to its singular form. + + Args: + resource: Plural resource name (e.g., 'users', 'user_identities', 'identities') + + Returns: + Singular form of the resource name (e.g., 'user', 'user_identity', 'identity') + """ + # Handle special cases + if resource == 'business': + return 'business' # Don't remove 's' from 'business' + elif resource == 'user_identities': + return 'user_identity' # Replace 'identities' with 'identity' + elif resource == 'identities': + return 'identity' # Replace 'identities' with 'identity' + # Default: remove trailing 's' if present + elif resource.endswith('s'): + return resource[:-1] + else: + return resource + def _generate_methods(self): """Generate dynamic methods for each API endpoint.""" for resource, endpoints in self.API_ENDPOINTS.items(): - # Handle special cases for singularization - if resource == 'business': - resource_singular = 'business' # Don't remove 's' from 'business' - else: - resource_singular = resource[:-1] if resource.endswith('s') else resource + resource_singular = self._singularize_resource(resource) for action, endpoint in endpoints.items(): if len(endpoint) == 3: @@ -427,11 +446,7 @@ def _create_api_method(self, http_method: str, path: str, resource: str, action: Returns: A callable method that makes the API request """ - # Handle special cases for singularization - if resource == 'business': - resource_singular = 'business' # Don't remove 's' from 'business' - else: - resource_singular = resource[:-1] if resource.endswith('s') else resource + resource_singular = self._singularize_resource(resource) def api_method(*args, **kwargs) -> Dict[str, Any]: # Format path with any path parameters from args From 65f0413c9c3dc58437914ed4bef4ab88bfad8cac Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Wed, 26 Nov 2025 19:40:30 +0200 Subject: [PATCH 3/5] test: update tests to match PR #128 API endpoint changes Update test assertions to reflect removed endpoints: - Remove get_permission assertion (permissions no longer has get endpoint) - Remove get_feature_flags and get_feature_flag assertions (removed in PR #128) - Remove update_api_application assertion (removed in PR #128) - Update test_feature_flags_api_calls to test create_feature_flag instead These changes align tests with the updated Management API endpoints introduced in PR #128. --- .../test_management_client.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/testv2/testv2_management/test_management_client.py b/testv2/testv2_management/test_management_client.py index 9373e88e..65ff926e 100644 --- a/testv2/testv2_management/test_management_client.py +++ b/testv2/testv2_management/test_management_client.py @@ -97,14 +97,13 @@ def test_dynamic_method_generation(self, mock_token_manager_class, mock_api_clie # Test permission methods assert hasattr(client, 'get_permissions') - assert hasattr(client, 'get_permission') + # Note: get_permission was removed in PR #128 - permissions no longer has a get endpoint assert hasattr(client, 'create_permission') assert hasattr(client, 'update_permission') assert hasattr(client, 'delete_permission') # Test feature flag methods - assert hasattr(client, 'get_feature_flags') - assert hasattr(client, 'get_feature_flag') + # Note: get_feature_flags and get_feature_flag were removed in PR #128 assert hasattr(client, 'create_feature_flag') assert hasattr(client, 'update_feature_flag') assert hasattr(client, 'delete_feature_flag') @@ -117,7 +116,7 @@ def test_dynamic_method_generation(self, mock_token_manager_class, mock_api_clie assert hasattr(client, 'get_api_applications') assert hasattr(client, 'get_api_application') assert hasattr(client, 'create_api_application') - assert hasattr(client, 'update_api_application') + # Note: update_api_application was removed in PR #128 assert hasattr(client, 'delete_api_application') # Test subscriber methods @@ -499,20 +498,21 @@ def test_feature_flags_api_calls(self, mock_token_manager_class, mock_api_client # Mock param_serialize to return expected values mock_api_client_instance.param_serialize.return_value = ( - 'GET', 'https://test.kinde.com/api/v1/feature-flags', {}, None, None + 'POST', 'https://test.kinde.com/api/v1/feature_flags', {}, + {"key": "test_flag", "type": "str", "value": "test_value"}, None ) # Mock REST client response mock_rest_response = Mock() mock_rest_response.read.return_value = None mock_rest_response.status = 200 - mock_rest_response.data = b'{"feature_flags": [{"key": "test_flag"}]}' + mock_rest_response.data = b'{"key": "test_flag", "type": "str", "value": "test_value"}' mock_rest_response.getheader.return_value = 'application/json' mock_api_client_instance.rest_client.request.return_value = mock_rest_response # Mock response_deserialize - expected_response = {"feature_flags": [{"key": "test_flag"}]} + expected_response = {"key": "test_flag", "type": "str", "value": "test_value"} mock_api_response = Mock() mock_api_response.data = expected_response mock_api_client_instance.response_deserialize.return_value = mock_api_response @@ -523,8 +523,8 @@ def test_feature_flags_api_calls(self, mock_token_manager_class, mock_api_client # Create client client = ManagementClient(self.domain, self.client_id, self.client_secret) - # Test feature flag API call - result = client.get_feature_flags() + # Test feature flag create API call (get_feature_flags was removed in PR #128) + result = client.create_feature_flag(key="test_flag", type="str", value="test_value") # Verify param_serialize was called mock_api_client_instance.param_serialize.assert_called_once() From 64df8e6b02adb40658be121cfa8e92560beeaa7c Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Wed, 26 Nov 2025 19:51:44 +0200 Subject: [PATCH 4/5] feat: add missing list endpoint for feature_flags Add the missing 'list' endpoint to feature_flags resource to enable get_feature_flags() method generation. Changes: - Add 'list': ('GET', '/api/v1/feature_flags') to feature_flags API_ENDPOINTS - Add corresponding response type mapping: 'list': {'200': 'GetFeatureFlagsResponse', ...} - Update test to assert get_feature_flags method exists This addresses the CodeRabbit review comment on PR #143 and enables the SDK to generate the get_feature_flags() method as documented in the Kinde Management API. --- kinde_sdk/management/management_client.py | 2 ++ testv2/testv2_management/test_management_client.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 60ad55ba..700292d9 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -84,6 +84,7 @@ class ManagementClient: # Feature Flags API 'feature_flags': { + 'list': ('GET', '/api/v1/feature_flags'), 'create': ('POST', '/api/v1/feature_flags'), 'update': ('PUT', '/api/v1/feature_flags/{feature_flag_key}'), 'delete': ('DELETE', '/api/v1/feature_flags/{feature_flag_key}'), @@ -261,6 +262,7 @@ class ManagementClient: 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'feature_flags': { + 'list': {'200': 'GetFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, diff --git a/testv2/testv2_management/test_management_client.py b/testv2/testv2_management/test_management_client.py index 65ff926e..54df9e1c 100644 --- a/testv2/testv2_management/test_management_client.py +++ b/testv2/testv2_management/test_management_client.py @@ -103,7 +103,8 @@ def test_dynamic_method_generation(self, mock_token_manager_class, mock_api_clie assert hasattr(client, 'delete_permission') # Test feature flag methods - # Note: get_feature_flags and get_feature_flag were removed in PR #128 + assert hasattr(client, 'get_feature_flags') + # Note: get_feature_flag was removed in PR #128 assert hasattr(client, 'create_feature_flag') assert hasattr(client, 'update_feature_flag') assert hasattr(client, 'delete_feature_flag') From dafb06bffca6b2c8d2de8a43a2b93b0542e3151d Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Thu, 27 Nov 2025 19:15:11 +0200 Subject: [PATCH 5/5] fix: update organization and API application endpoint paths and response types - Corrected endpoint paths for organizations and API applications to use plural forms. - Updated response types for create endpoints to reflect correct HTTP status codes (201). - Adjusted test assertions to ensure alignment with the updated API structure. These changes enhance consistency with the Kinde Management API specifications. --- kinde_sdk/management/management_client.py | 14 +++++++------- testv2/testv2_management/test_management_client.py | 5 +---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 700292d9..5d27e3f3 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -37,10 +37,10 @@ class ManagementClient: # Organizations API 'organizations': { 'list': ('GET', '/api/v1/organizations'), - 'get': ('GET', '/api/v1/organization/{org_code}'), - 'create': ('POST', '/api/v1/organization'), - 'update': ('PATCH', '/api/v1/organization/{org_code}'), - 'delete': ('DELETE', '/api/v1/organization/{org_code}'), + 'get': ('GET', '/api/v1/organizations/{org_code}'), + 'create': ('POST', '/api/v1/organizations'), + 'update': ('PATCH', '/api/v1/organizations/{org_code}'), + 'delete': ('DELETE', '/api/v1/organizations/{org_code}'), }, # Organization Users API @@ -228,7 +228,7 @@ class ManagementClient: 'organizations': { 'list': {'200': 'GetOrganizationsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'200': 'CreateOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'201': 'CreateOrganizationResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, @@ -275,7 +275,7 @@ class ManagementClient: 'api_applications': { 'list': {'200': 'GetApisResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetApiResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, - 'create': {'200': 'CreateApisResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, + 'create': {'201': 'CreateApisResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'connected_apps': { @@ -319,7 +319,7 @@ class ManagementClient: }, 'connections': { 'list': {'200': 'GetConnectionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, - 'get': {'200': 'Connection', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, + 'get': {'200': 'GetConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'create': {'201': 'CreateConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, diff --git a/testv2/testv2_management/test_management_client.py b/testv2/testv2_management/test_management_client.py index 54df9e1c..68eed6b3 100644 --- a/testv2/testv2_management/test_management_client.py +++ b/testv2/testv2_management/test_management_client.py @@ -97,14 +97,12 @@ def test_dynamic_method_generation(self, mock_token_manager_class, mock_api_clie # Test permission methods assert hasattr(client, 'get_permissions') - # Note: get_permission was removed in PR #128 - permissions no longer has a get endpoint assert hasattr(client, 'create_permission') assert hasattr(client, 'update_permission') assert hasattr(client, 'delete_permission') # Test feature flag methods assert hasattr(client, 'get_feature_flags') - # Note: get_feature_flag was removed in PR #128 assert hasattr(client, 'create_feature_flag') assert hasattr(client, 'update_feature_flag') assert hasattr(client, 'delete_feature_flag') @@ -117,7 +115,6 @@ def test_dynamic_method_generation(self, mock_token_manager_class, mock_api_clie assert hasattr(client, 'get_api_applications') assert hasattr(client, 'get_api_application') assert hasattr(client, 'create_api_application') - # Note: update_api_application was removed in PR #128 assert hasattr(client, 'delete_api_application') # Test subscriber methods @@ -524,7 +521,7 @@ def test_feature_flags_api_calls(self, mock_token_manager_class, mock_api_client # Create client client = ManagementClient(self.domain, self.client_id, self.client_secret) - # Test feature flag create API call (get_feature_flags was removed in PR #128) + # Test feature flag create API call result = client.create_feature_flag(key="test_flag", type="str", value="test_value") # Verify param_serialize was called