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 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 From a1a140cad0e3f2dcd18771a1a7568baab0770099 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Sat, 17 Jan 2026 19:05:39 +0200 Subject: [PATCH 06/10] fix: correct roles.update status code from 201 to 200 Update roles.update response type mapping to use 200 instead of 201, as update operations return HTTP 200 OK, not 201 Created. This fixes silent deserialization failures where response_type would be None and callers would receive data=None instead of the actual response. Fixes issue identified in CodeRabbit review. --- kinde_sdk/management/management_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 5d27e3f3..80ff9172 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -252,7 +252,7 @@ class ManagementClient: 'list': {'200': 'GetRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'}, 'get': {'200': 'GetRoleResponse', '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'}, + 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'}, }, 'permissions': { From 99dccea76746ba6ad0e0f97ac39db811979a2659 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Sat, 17 Jan 2026 19:22:55 +0200 Subject: [PATCH 07/10] fix: correct feature_flags.update method and singularization logic - Change feature_flags.update HTTP method from PUT to PATCH to match API - Fix _singularize_resource to handle -ies endings correctly - properties -> property (was propertie) - user_properties -> user_property (was user_propertie) - organization_properties -> organization_property (was organization_propertie) Fixes issues identified in CodeRabbit review: - Critical: Update operations should use PATCH, not PUT - Major: Singularization fails for words ending in '-ies' --- kinde_sdk/management/management_client.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 80ff9172..41106559 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -86,7 +86,7 @@ class ManagementClient: 'feature_flags': { 'list': ('GET', '/api/v1/feature_flags'), 'create': ('POST', '/api/v1/feature_flags'), - 'update': ('PUT', '/api/v1/feature_flags/{feature_flag_key}'), + 'update': ('PATCH', '/api/v1/feature_flags/{feature_flag_key}'), 'delete': ('DELETE', '/api/v1/feature_flags/{feature_flag_key}'), }, @@ -403,6 +403,14 @@ def _singularize_resource(self, resource: str) -> str: return 'user_identity' # Replace 'identities' with 'identity' elif resource == 'identities': return 'identity' # Replace 'identities' with 'identity' + # Handle words ending in '-ies' (e.g., properties -> property, user_properties -> user_property) + elif resource.endswith('ies'): + # For compound names, only replace the last part + if '_' in resource: + parts = resource.rsplit('_', 1) + return f"{parts[0]}_{parts[1][:-3]}y" + else: + return resource[:-3] + 'y' # Default: remove trailing 's' if present elif resource.endswith('s'): return resource[:-1] From 8460d1d91d73ba659a218e09e05c540eb0d8bb61 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Sat, 17 Jan 2026 19:34:05 +0200 Subject: [PATCH 08/10] fix: change properties.update HTTP method from PUT to PATCH The official Kinde Management API documentation specifies PATCH for the properties update endpoint. Using PUT results in HTTP 405 Method Not Allowed errors. Fixes critical issue identified in CodeRabbit review. --- kinde_sdk/management/management_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 41106559..4017134a 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -128,7 +128,7 @@ class ManagementClient: 'properties': { 'list': ('GET', '/api/v1/properties'), 'create': ('POST', '/api/v1/properties'), - 'update': ('PUT', '/api/v1/properties/{property_id}'), + 'update': ('PATCH', '/api/v1/properties/{property_id}'), 'delete': ('DELETE', '/api/v1/properties/{property_id}'), }, From 4948b4d37474cba7be302d5910d2587050470db4 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Sat, 17 Jan 2026 19:42:52 +0200 Subject: [PATCH 09/10] fix: add missing 404 error response handling for identities endpoints Add 404 error response mappings to identities.get, identities.update, and identities.delete to match the pattern used by other similar endpoints for proper not found scenario handling. Fixes minor issue identified in CodeRabbit review. --- kinde_sdk/management/management_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 4017134a..25f22865 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -352,9 +352,9 @@ class ManagementClient: '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'}, + 'get': {'200': 'Identity', '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'}, }, } From d1e55e35596d2f6d918e6176a28927a6e410b0c6 Mon Sep 17 00:00:00 2001 From: brandtkruger Date: Sat, 17 Jan 2026 19:47:51 +0200 Subject: [PATCH 10/10] fix: change user_properties and organization_properties update methods to PATCH Change user_properties.update and organization_properties.update HTTP methods from PUT to PATCH to match the Kinde Management API specification. This is also consistent with the main properties.update endpoint which uses PATCH. Using PUT causes HTTP errors. The API documentation specifies PATCH for these endpoints. Fixes issue identified in CodeRabbit review. --- kinde_sdk/management/management_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kinde_sdk/management/management_client.py b/kinde_sdk/management/management_client.py index 25f22865..16698a0d 100644 --- a/kinde_sdk/management/management_client.py +++ b/kinde_sdk/management/management_client.py @@ -135,13 +135,13 @@ class ManagementClient: # User Properties API 'user_properties': { 'list': ('GET', '/api/v1/users/{user_id}/properties'), - 'update': ('PUT', '/api/v1/users/{user_id}/properties/{property_key}'), + 'update': ('PATCH', '/api/v1/users/{user_id}/properties/{property_key}'), }, # Organization Properties API 'organization_properties': { 'list': ('GET', '/api/v1/organizations/{org_code}/properties'), - 'update': ('PUT', '/api/v1/organizations/{org_code}/properties/{property_key}'), + 'update': ('PATCH', '/api/v1/organizations/{org_code}/properties/{property_key}'), }, # Webhooks API