kinde-python-sdk 2.0.6__py3-none-any.whl → 2.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,12 +40,33 @@ async def home(request: Request):
40
40
  if kinde_oauth.is_authenticated():
41
41
  user = kinde_oauth.get_user_info()
42
42
 
43
+ # Validate environment variables
44
+ domain = os.getenv("KINDE_DOMAIN")
45
+ client_id = os.getenv("KINDE_MANAGEMENT_CLIENT_ID")
46
+ client_secret = os.getenv("KINDE_MANAGEMENT_CLIENT_SECRET")
47
+
48
+ if not all([domain, client_id, client_secret]):
49
+ return """
50
+ <html>
51
+ <body>
52
+ <h1>Configuration Error</h1>
53
+ <p>Missing required environment variables for management client.</p>
54
+ <a href="/logout">Logout</a>
55
+ </body>
56
+ </html>
57
+ """
58
+
43
59
  management_client = ManagementClient(
44
- domain=os.getenv("KINDE_DOMAIN"),
45
- client_id=os.getenv("KINDE_MANAGEMENT_CLIENT_ID"),
46
- client_secret=os.getenv("KINDE_MANAGEMENT_CLIENT_SECRET")
60
+ domain=domain,
61
+ client_id=client_id,
62
+ client_secret=client_secret
47
63
  )
48
- api_response = management_client.get_users()
64
+ try:
65
+ api_response = management_client.get_users()
66
+ user_count = len(api_response.users) if hasattr(api_response, 'users') else 0
67
+ except Exception as e:
68
+ logger.error(f"Failed to fetch users: {e}")
69
+ user_count = 0
49
70
 
50
71
  return f"""
51
72
  <html>
@@ -55,7 +76,7 @@ async def home(request: Request):
55
76
  <p>feature flags: {await feature_flags.get_all_flags()}</p>
56
77
  <p>permissions: {await permissions.get_permissions()}</p>
57
78
  <p>tokens: {tokens.get_token_manager().get_access_token()}</p>
58
- <p>tokens: {api_response}</p>
79
+ <p>users: {user_count} user(s) found</p>
59
80
  <p>You are logged in.</p>
60
81
  <a href="/logout">Logout</a>
61
82
  </body>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kinde-python-sdk
3
- Version: 2.0.6
3
+ Version: 2.0.8
4
4
  Summary: Connect your app to the Kinde platform
5
5
  Author-email: Kinde Engineering <engineering@kinde.com>
6
6
  Project-URL: Homepage, https://github.com/kinde-oss/kinde-python-sdk
@@ -1,5 +1,5 @@
1
1
  kinde_fastapi/__init__.py,sha256=FzB0zDBbzaLLvGZBPrBZN94I6LRZdkT4RSmGUsbh3mA,470
2
- kinde_fastapi/examples/example_app.py,sha256=YFsjNnTiofR8W16NONvgCKbX_PSFNWg2kF-X-vwuTvc,2306
2
+ kinde_fastapi/examples/example_app.py,sha256=OVJDFKzT3Qv_tA4GgizW2DmjoE0hm_9O4H_DKIGYNeQ,3057
3
3
  kinde_fastapi/examples/session.py,sha256=WblGM7TM2JCKdSFsd2OmSP0daexZ7E6ZS1xgTQY_etY,2472
4
4
  kinde_fastapi/framework/__init__.py,sha256=tpTI84q7HCHMlREslMrngIlKwC8CDog9bEMI_ydhCUs,181
5
5
  kinde_fastapi/framework/fastapi_framework.py,sha256=-MiBFddfY3NiB9BE_b8BBYAxfGbhOQKO-RXUsCu4a3U,6767
@@ -13,7 +13,7 @@ kinde_flask/framework/flask_framework.py,sha256=I4dVWmkyd0FBqjAkOyftebm7_qpI9uxk
13
13
  kinde_flask/framework/flask_framework_factory.py,sha256=ALpsj-cHBox3ktRxi-CyZ5Q6EOvacfdu4pvlTYkuviA,802
14
14
  kinde_flask/middleware/framework_middleware.py,sha256=XFK6kgMDuHkrawDJ0_MMgLO7es0YQVjlVDDRDgwlCJ0,1012
15
15
  kinde_flask/storage/flask_storage_factory.py,sha256=MitOUbfCbfvSQFFoUbbnbXLEOL_qajS29Mlsn0TyTsY,2562
16
- kinde_python_sdk-2.0.6.dist-info/licenses/LICENSE,sha256=iT6AIO6NJn_mo0kDD5mpz2zp9GpzH6YdhqOmkCBg-kQ,1385
16
+ kinde_python_sdk-2.0.8.dist-info/licenses/LICENSE,sha256=iT6AIO6NJn_mo0kDD5mpz2zp9GpzH6YdhqOmkCBg-kQ,1385
17
17
  kinde_sdk/__init__.py,sha256=Mh3eVcnJDk-KdQfxVUsF19NgBYexoJCwG5iAbD1LEdQ,1052
18
18
  kinde_sdk/api_client.py,sha256=GEb1BIjvIrUe8mFIr7hppp2PO604BiSlAr0_TYBfuy4,58496
19
19
  kinde_sdk/configuration.py,sha256=oqZGvKEf4kNNURbI1pip2ZVVcDyRTSmmnjXWziH4s80,15765
@@ -109,7 +109,7 @@ kinde_sdk/apis/tags/users_api.py,sha256=06qeWo8ZNNZvKQ5hl0ImtPvNSbzDKkceZj7ACrlu
109
109
  kinde_sdk/apis/tags/webhooks_api.py,sha256=AmLDLeW6aLz3lnqUGGd2dpVxuVKxW1KgIW2rdtUNJmw,925
110
110
  kinde_sdk/auth/__init__.py,sha256=czQs-NJ3R22EXkcnszl3YJKmjsB-mVpJ4T11zbRb_4Y,379
111
111
  kinde_sdk/auth/base_auth.py,sha256=hV-xjaGa35YMDFpmEWQgTNM7w6ZHskLm_p5cnXSSLJY,1253
112
- kinde_sdk/auth/claims.py,sha256=g0vlQtHBNyuELCNSTuahr3ZhBma4Htp2KjKCtKq1f90,1540
112
+ kinde_sdk/auth/claims.py,sha256=sS4cvtEYQyTlT4WacibyKzp-5eTTH4JbMnDabMTX31w,1560
113
113
  kinde_sdk/auth/config_loader.py,sha256=L01kqmzUMKQ0X_PA9MYcWSeJiVoDfrB4RANQGWS76UA,879
114
114
  kinde_sdk/auth/enums.py,sha256=Xbk7jwXtq_TViZSfBy6h9lon8VEA5v6ssUl-3yKp8Zk,538
115
115
  kinde_sdk/auth/feature_flags.py,sha256=VSqfyqNmYLo3Q74nyo4L8W8jt8msZ_v-45Y7pW_48VA,3810
@@ -117,7 +117,7 @@ kinde_sdk/auth/login_options.py,sha256=3Fvbo-rjLzbV14Np48Ogw0HieThjlRtfP4VHztJtG
117
117
  kinde_sdk/auth/oauth.py,sha256=bXWM6Mo7H8EgrD2GSOfhibvwz6MVMPe7-wM1PaL6_6o,26136
118
118
  kinde_sdk/auth/permissions.py,sha256=A9BmGt3OokuvS-4twveCZdCPFY-QobyzqlgGVo8eSoI,1913
119
119
  kinde_sdk/auth/portals.py,sha256=Z3goLvio-Xw7VjTRrQZXKOFkTMvtF78nKzFF5-u4rkY,4530
120
- kinde_sdk/auth/token_manager.py,sha256=uG9TFcJ_K4hbgFEP9gy_S1xRUBpzD5ZYT37LzMWoWHA,7182
120
+ kinde_sdk/auth/token_manager.py,sha256=HSfyKmc4kyoQz2NeRPVWtpY4E4rtf2w6SWArRlQ7-5s,8278
121
121
  kinde_sdk/auth/tokens.py,sha256=eZKJTTw764FrzvxurWNee1_ZX1Q2FQjJUXBlsMlp2A0,2367
122
122
  kinde_sdk/auth/user_session.py,sha256=CmFotC9ONzHwPMRJy4SOT7tOI_63dHv_ttpdNHssH8Y,7657
123
123
  kinde_sdk/core/__init__.py,sha256=ejO0P_oXuiO5V-MJVRqKu6y0fAWKyi4iL2UIRGXhLy0,358
@@ -140,7 +140,7 @@ kinde_sdk/management/api_client.py,sha256=EOtJwSwec5DpyJ0_Hv8wqb0ZnEPMJDvbMx5dkp
140
140
  kinde_sdk/management/api_response.py,sha256=eMxw1mpmJcoGZ3gs9z6jM4oYoZ10Gjk333s9sKxGv7s,652
141
141
  kinde_sdk/management/configuration.py,sha256=icAfQBYmokmspDa_ELha2Qfeq_IkgAp6COdmw1ZpL2Q,18909
142
142
  kinde_sdk/management/exceptions.py,sha256=I_xzvCXjHszPUrUr4dNsE9Pg-nH58YszF075NvjSRMA,6780
143
- kinde_sdk/management/management_client.py,sha256=gjUIyw0jedoKGyLeFNFcWFEjn9fVW-VzV9OJH-t-LFU,19099
143
+ kinde_sdk/management/management_client.py,sha256=_GErLV96nTbWw58fscCrDe_UOVk25u4Vlx0amFp3g6Y,31467
144
144
  kinde_sdk/management/management_token_manager.py,sha256=uEYQBiN5mNqZujTSYcU2sl2Sk51YwSe9_b-XkDq4uAI,9853
145
145
  kinde_sdk/management/rest.py,sha256=7kMCS7NAOYCI4hrThABWpV-AN0Y-LuCjMnJ404CJdq8,9783
146
146
  kinde_sdk/management/schemas.py,sha256=6tg1tEh8IL-9UuZiWFVe-0Pu-TD-CYW37soeQ6AyspA,97671
@@ -722,7 +722,7 @@ kinde_sdk/test/test_models/test_user_profile_v2.py,sha256=QzYjvjtTGa1ktE5ruyGBm_
722
722
  kinde_sdk/test/test_models/test_users.py,sha256=wJQR5K7dsfHQQsOQp4mrHWQynFPHwL-gDtbgVifNfMs,537
723
723
  kinde_sdk/test/test_models/test_users_response.py,sha256=BCcKxe9GctDrOXOzw0Q7O1ijKy_93Oj3E2wHW00y624,869
724
724
  kinde_sdk/test/test_models/test_webhook.py,sha256=KNfR8sKAK5H2vX_cXYGT5EfgaVP7_egC39uY6-s-4qo,544
725
- kinde_python_sdk-2.0.6.dist-info/METADATA,sha256=GREjlpoAvDzO3R8P_0mygk0F50j8ZMZDgFx2hAHNsbY,23482
726
- kinde_python_sdk-2.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
727
- kinde_python_sdk-2.0.6.dist-info/top_level.txt,sha256=TUU3EVjV6O4brF-mooQr6pnTk-jXJphmIWRHCIdyIgI,36
728
- kinde_python_sdk-2.0.6.dist-info/RECORD,,
725
+ kinde_python_sdk-2.0.8.dist-info/METADATA,sha256=IpZmsHIm-6tEYfeHhPWBBWmrepU4Wez1j90Y98KKPCQ,23482
726
+ kinde_python_sdk-2.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
727
+ kinde_python_sdk-2.0.8.dist-info/top_level.txt,sha256=TUU3EVjV6O4brF-mooQr6pnTk-jXJphmIWRHCIdyIgI,36
728
+ kinde_python_sdk-2.0.8.dist-info/RECORD,,
kinde_sdk/auth/claims.py CHANGED
@@ -24,7 +24,7 @@ class Claims(BaseAuth):
24
24
  "value": None
25
25
  }
26
26
 
27
- claims = token_manager.get_claims()
27
+ claims = token_manager.get_claims(token_type)
28
28
  value = claims.get(claim_name)
29
29
 
30
30
  return {
@@ -46,7 +46,7 @@ class Claims(BaseAuth):
46
46
  if not token_manager:
47
47
  return {}
48
48
 
49
- return token_manager.get_claims()
49
+ return token_manager.get_claims(token_type)
50
50
 
51
51
  # Create a singleton instance
52
52
  claims = Claims()
@@ -153,17 +153,46 @@ class TokenManager:
153
153
  """Get the ID token if available."""
154
154
  return self.tokens.get("id_token")
155
155
 
156
- def get_claims(self):
157
- """Get the claims from the access token if available, falling back to ID token claims."""
158
- # First try to get claims from access token
159
- claims = self.tokens.get("access_token_claims", {})
156
+ def get_claims(self, token_type: str = "access_token"):
157
+ """Get the claims from the specified token type.
158
+
159
+ Args:
160
+ token_type (str): The type of token to get claims from.
161
+ Valid values are "access_token" or "id_token".
162
+
163
+ Returns:
164
+ dict: The claims from the specified token, or empty dict if not available.
165
+ """
166
+ # Validate token type
167
+ valid_token_types = ["access_token", "id_token"]
168
+ if token_type not in valid_token_types:
169
+ logging.warning(f"Invalid token_type '{token_type}'. Valid types are: {valid_token_types}")
170
+ return {}
171
+
172
+ # Use f-string for safer string formatting
173
+ claims_key = f"{token_type}_claims"
174
+ claims = self.tokens.get(claims_key, {})
175
+
160
176
  if not claims:
161
- # Fall back to ID token claims if access token claims are not available
162
- claims = self.tokens.get("id_token_claims", {})
163
- if not claims:
164
- logging.warning("No claims available in token manager")
177
+ logging.warning(f"No claims available for token type: {token_type}")
178
+
165
179
  return claims
166
180
 
181
+ def get_claim(self, key: str, token_type: str = "access_token"):
182
+ """Get a specific claim from the specified token type.
183
+
184
+ Args:
185
+ key (str): The claim key to retrieve
186
+ token_type (str): The type of token to get the claim from.
187
+ Valid values are "access_token" or "id_token".
188
+
189
+ Returns:
190
+ dict: Dictionary containing the claim name and value, or empty dict if not found.
191
+ """
192
+ claims = self.get_claims(token_type)
193
+ value = claims.get(key)
194
+ return {"name": key, "value": value}
195
+
167
196
  def revoke_token(self):
168
197
  """ Revoke the current access token. """
169
198
  if "access_token" not in self.tokens:
@@ -43,6 +43,28 @@ class ManagementClient:
43
43
  'delete': ('DELETE', '/api/v1/organizations/{org_code}'),
44
44
  },
45
45
 
46
+ # Organization Users API
47
+ 'organization_users': {
48
+ 'list': ('GET', '/api/v1/organizations/{org_code}/users'),
49
+ 'add': ('POST', '/api/v1/organizations/{org_code}/users'),
50
+ 'update': ('PATCH', '/api/v1/organizations/{org_code}/users'),
51
+ 'remove': ('DELETE', '/api/v1/organizations/{org_code}/users/{user_id}'),
52
+ },
53
+
54
+ # Organization User Roles API
55
+ 'organization_user_roles': {
56
+ 'list': ('GET', '/api/v1/organizations/{org_code}/users/{user_id}/roles'),
57
+ 'add': ('POST', '/api/v1/organizations/{org_code}/users/{user_id}/roles'),
58
+ 'remove': ('DELETE', '/api/v1/organizations/{org_code}/users/{user_id}/roles/{role_id}'),
59
+ },
60
+
61
+ # Organization User Permissions API
62
+ 'organization_user_permissions': {
63
+ 'list': ('GET', '/api/v1/organizations/{org_code}/users/{user_id}/permissions'),
64
+ 'add': ('POST', '/api/v1/organizations/{org_code}/users/{user_id}/permissions'),
65
+ 'remove': ('DELETE', '/api/v1/organizations/{org_code}/users/{user_id}/permissions/{permission_id}'),
66
+ },
67
+
46
68
  # Roles API
47
69
  'roles': {
48
70
  'list': ('GET', '/api/v1/roles'),
@@ -103,6 +125,94 @@ class ManagementClient:
103
125
  'industries': {
104
126
  'list': ('GET', '/api/v1/industries'),
105
127
  },
128
+
129
+ # Properties API
130
+ 'properties': {
131
+ 'list': ('GET', '/api/v1/properties'),
132
+ 'get': ('GET', '/api/v1/properties/{property_id}'),
133
+ 'create': ('POST', '/api/v1/properties'),
134
+ 'update': ('PATCH', '/api/v1/properties/{property_id}'),
135
+ 'delete': ('DELETE', '/api/v1/properties/{property_id}'),
136
+ },
137
+
138
+ # User Properties API
139
+ 'user_properties': {
140
+ 'list': ('GET', '/api/v1/users/{user_id}/properties'),
141
+ 'get': ('GET', '/api/v1/users/{user_id}/properties/{property_key}'),
142
+ 'update': ('PUT', '/api/v1/users/{user_id}/properties/{property_key}'),
143
+ },
144
+
145
+ # Organization Properties API
146
+ 'organization_properties': {
147
+ 'list': ('GET', '/api/v1/organizations/{org_code}/properties'),
148
+ 'get': ('GET', '/api/v1/organizations/{org_code}/properties/{property_key}'),
149
+ 'update': ('PUT', '/api/v1/organizations/{org_code}/properties/{property_key}'),
150
+ },
151
+
152
+ # Webhooks API
153
+ 'webhooks': {
154
+ 'list': ('GET', '/api/v1/webhooks'),
155
+ 'get': ('GET', '/api/v1/webhooks/{webhook_id}'),
156
+ 'create': ('POST', '/api/v1/webhooks'),
157
+ 'update': ('PATCH', '/api/v1/webhooks/{webhook_id}'),
158
+ 'delete': ('DELETE', '/api/v1/webhooks/{webhook_id}'),
159
+ },
160
+
161
+ # Events API
162
+ 'events': {
163
+ 'get': ('GET', '/api/v1/events/{event_id}'),
164
+ },
165
+
166
+ # Event Types API
167
+ 'event_types': {
168
+ 'list': ('GET', '/api/v1/event_types'),
169
+ },
170
+
171
+ # Connections API
172
+ 'connections': {
173
+ 'list': ('GET', '/api/v1/connections'),
174
+ 'get': ('GET', '/api/v1/connections/{connection_id}'),
175
+ 'create': ('POST', '/api/v1/connections'),
176
+ 'update': ('PATCH', '/api/v1/connections/{connection_id}'),
177
+ 'delete': ('DELETE', '/api/v1/connections/{connection_id}'),
178
+ },
179
+
180
+ # Business API
181
+ 'business': {
182
+ 'get': ('GET', '/api/v1/business'),
183
+ },
184
+
185
+ # Environment Feature Flags API
186
+ 'environment_feature_flags': {
187
+ 'list': ('GET', '/api/v1/environment/feature_flags'),
188
+ 'get': ('GET', '/api/v1/environment/feature_flags/{feature_flag_key}'),
189
+ 'update': ('PATCH', '/api/v1/environment/feature_flags/{feature_flag_key}'),
190
+ 'delete': ('DELETE', '/api/v1/environment/feature_flags/{feature_flag_key}'),
191
+ },
192
+
193
+ # Organization Feature Flags API
194
+ 'organization_feature_flags': {
195
+ 'list': ('GET', '/api/v1/organizations/{org_code}/feature_flags'),
196
+ 'get': ('GET', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'),
197
+ 'update': ('PATCH', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'),
198
+ 'delete': ('DELETE', '/api/v1/organizations/{org_code}/feature_flags/{feature_flag_key}'),
199
+ },
200
+
201
+ # User Feature Flags API
202
+ 'user_feature_flags': {
203
+ 'get': ('GET', '/api/v1/users/{user_id}/feature_flags/{feature_flag_key}'),
204
+ 'update': ('PATCH', '/api/v1/users/{user_id}/feature_flags/{feature_flag_key}'),
205
+ },
206
+
207
+ # User Password API
208
+ 'user_password': {
209
+ 'update': ('PUT', '/api/v1/users/{user_id}/password'),
210
+ },
211
+
212
+ # User Refresh Claims API
213
+ 'user_refresh_claims': {
214
+ 'refresh': ('POST', '/api/v1/users/{user_id}/refresh_claims'),
215
+ },
106
216
  }
107
217
 
108
218
  # Define response types for each endpoint
@@ -121,6 +231,22 @@ class ManagementClient:
121
231
  'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
122
232
  'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
123
233
  },
234
+ 'organization_users': {
235
+ 'list': {'200': 'GetOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
236
+ 'add': {'201': 'AddOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
237
+ 'update': {'200': 'UpdateOrganizationUsersResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
238
+ 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
239
+ },
240
+ 'organization_user_roles': {
241
+ 'list': {'200': 'GetOrganizationsUserRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
242
+ 'add': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
243
+ 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
244
+ },
245
+ 'organization_user_permissions': {
246
+ 'list': {'200': 'GetOrganizationsUserPermissionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
247
+ 'add': {'201': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
248
+ 'remove': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
249
+ },
124
250
  'roles': {
125
251
  'list': {'200': 'GetRolesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
126
252
  'get': {'200': 'GetRoleResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
@@ -166,6 +292,68 @@ class ManagementClient:
166
292
  'industries': {
167
293
  'list': {'200': 'GetIndustriesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
168
294
  },
295
+ 'properties': {
296
+ 'list': {'200': 'GetPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
297
+ 'get': {'200': 'GetPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
298
+ 'create': {'201': 'CreatePropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
299
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
300
+ 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
301
+ },
302
+ 'user_properties': {
303
+ 'list': {'200': 'GetUserPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
304
+ 'get': {'200': 'GetUserPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
305
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
306
+ },
307
+ 'organization_properties': {
308
+ 'list': {'200': 'GetOrganizationPropertiesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
309
+ 'get': {'200': 'GetOrganizationPropertyResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
310
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
311
+ },
312
+ 'webhooks': {
313
+ 'list': {'200': 'GetWebhooksResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
314
+ 'get': {'200': 'GetWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
315
+ 'create': {'201': 'CreateWebhookResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
316
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
317
+ 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
318
+ },
319
+ 'events': {
320
+ 'get': {'200': 'GetEventResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
321
+ },
322
+ 'event_types': {
323
+ 'list': {'200': 'GetEventTypesResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
324
+ },
325
+ 'connections': {
326
+ 'list': {'200': 'GetConnectionsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
327
+ 'get': {'200': 'GetConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
328
+ 'create': {'201': 'CreateConnectionResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
329
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
330
+ 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
331
+ },
332
+ 'business': {
333
+ 'get': {'200': 'GetBusinessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
334
+ },
335
+ 'environment_feature_flags': {
336
+ 'list': {'200': 'GetEnvironmentFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
337
+ 'get': {'200': 'GetEnvironmentFeatureFlagsResponseDataFeatureFlagsInner', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
338
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
339
+ 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
340
+ },
341
+ 'organization_feature_flags': {
342
+ 'list': {'200': 'GetOrganizationFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '429': 'ErrorResponse'},
343
+ 'get': {'200': 'GetOrganizationFeatureFlagsResponseDataFeatureFlagsInner', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
344
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
345
+ 'delete': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
346
+ },
347
+ 'user_feature_flags': {
348
+ 'get': {'200': 'GetUserFeatureFlagsResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
349
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
350
+ },
351
+ 'user_password': {
352
+ 'update': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
353
+ },
354
+ 'user_refresh_claims': {
355
+ 'refresh': {'200': 'SuccessResponse', '400': 'ErrorResponse', '403': 'ErrorResponse', '404': 'ErrorResponse', '429': 'ErrorResponse'},
356
+ },
169
357
  }
170
358
 
171
359
  def __init__(self, domain: str, client_id: str, client_secret: str):
@@ -199,7 +387,11 @@ class ManagementClient:
199
387
  def _generate_methods(self):
200
388
  """Generate dynamic methods for each API endpoint."""
201
389
  for resource, endpoints in self.API_ENDPOINTS.items():
202
- resource_singular = resource[:-1] if resource.endswith('s') else resource
390
+ # Handle special cases for singularization
391
+ if resource == 'business':
392
+ resource_singular = 'business' # Don't remove 's' from 'business'
393
+ else:
394
+ resource_singular = resource[:-1] if resource.endswith('s') else resource
203
395
 
204
396
  for action, (method, path) in endpoints.items():
205
397
  # Create method name based on action and resource
@@ -229,7 +421,11 @@ class ManagementClient:
229
421
  Returns:
230
422
  A callable method that makes the API request
231
423
  """
232
- resource_singular = resource[:-1] if resource.endswith('s') else resource
424
+ # Handle special cases for singularization
425
+ if resource == 'business':
426
+ resource_singular = 'business' # Don't remove 's' from 'business'
427
+ else:
428
+ resource_singular = resource[:-1] if resource.endswith('s') else resource
233
429
 
234
430
  def api_method(*args, **kwargs) -> Dict[str, Any]:
235
431
  # Format path with any path parameters from args