authpi-admin 0.3.0__tar.gz

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.
Files changed (49) hide show
  1. authpi_admin-0.3.0/.gitignore +51 -0
  2. authpi_admin-0.3.0/CHANGELOG.md +25 -0
  3. authpi_admin-0.3.0/PKG-INFO +285 -0
  4. authpi_admin-0.3.0/README.md +253 -0
  5. authpi_admin-0.3.0/authpi_admin/__init__.py +55 -0
  6. authpi_admin-0.3.0/authpi_admin/_version.py +5 -0
  7. authpi_admin-0.3.0/authpi_admin/client.py +155 -0
  8. authpi_admin-0.3.0/authpi_admin/errors.py +218 -0
  9. authpi_admin-0.3.0/authpi_admin/generated/__init__.py +28 -0
  10. authpi_admin-0.3.0/authpi_admin/generated/models.py +380 -0
  11. authpi_admin-0.3.0/authpi_admin/generated/resources/__init__.py +0 -0
  12. authpi_admin-0.3.0/authpi_admin/generated/resources/accounts.py +157 -0
  13. authpi_admin-0.3.0/authpi_admin/generated/resources/agents.py +177 -0
  14. authpi_admin-0.3.0/authpi_admin/generated/resources/api_keys.py +213 -0
  15. authpi_admin-0.3.0/authpi_admin/generated/resources/approvals.py +109 -0
  16. authpi_admin-0.3.0/authpi_admin/generated/resources/auth_methods.py +148 -0
  17. authpi_admin-0.3.0/authpi_admin/generated/resources/clients.py +197 -0
  18. authpi_admin-0.3.0/authpi_admin/generated/resources/deliveries.py +83 -0
  19. authpi_admin-0.3.0/authpi_admin/generated/resources/domains.py +194 -0
  20. authpi_admin-0.3.0/authpi_admin/generated/resources/events.py +111 -0
  21. authpi_admin-0.3.0/authpi_admin/generated/resources/groups.py +160 -0
  22. authpi_admin-0.3.0/authpi_admin/generated/resources/invitations.py +202 -0
  23. authpi_admin-0.3.0/authpi_admin/generated/resources/issuers.py +157 -0
  24. authpi_admin-0.3.0/authpi_admin/generated/resources/members.py +154 -0
  25. authpi_admin-0.3.0/authpi_admin/generated/resources/notes.py +192 -0
  26. authpi_admin-0.3.0/authpi_admin/generated/resources/organizations.py +244 -0
  27. authpi_admin-0.3.0/authpi_admin/generated/resources/sessions.py +125 -0
  28. authpi_admin-0.3.0/authpi_admin/generated/resources/tokens.py +94 -0
  29. authpi_admin-0.3.0/authpi_admin/generated/resources/trusted_devices.py +102 -0
  30. authpi_admin-0.3.0/authpi_admin/generated/resources/users.py +224 -0
  31. authpi_admin-0.3.0/authpi_admin/generated/resources/verifiers.py +102 -0
  32. authpi_admin-0.3.0/authpi_admin/generated/resources/webhooks.py +167 -0
  33. authpi_admin-0.3.0/authpi_admin/generated/scopes/__init__.py +0 -0
  34. authpi_admin-0.3.0/authpi_admin/generated/scopes/agent_scope.py +84 -0
  35. authpi_admin-0.3.0/authpi_admin/generated/scopes/issuer_scope.py +160 -0
  36. authpi_admin-0.3.0/authpi_admin/generated/scopes/user_scope.py +102 -0
  37. authpi_admin-0.3.0/authpi_admin/generated/scopes/webhook_scope.py +84 -0
  38. authpi_admin-0.3.0/authpi_admin/http_client.py +305 -0
  39. authpi_admin-0.3.0/authpi_admin/pagination.py +41 -0
  40. authpi_admin-0.3.0/authpi_admin/py.typed +0 -0
  41. authpi_admin-0.3.0/authpi_admin/user_agent.py +21 -0
  42. authpi_admin-0.3.0/pyproject.toml +69 -0
  43. authpi_admin-0.3.0/tests/__init__.py +0 -0
  44. authpi_admin-0.3.0/tests/test_client.py +90 -0
  45. authpi_admin-0.3.0/tests/test_errors.py +193 -0
  46. authpi_admin-0.3.0/tests/test_http_client.py +461 -0
  47. authpi_admin-0.3.0/tests/test_integration.py +281 -0
  48. authpi_admin-0.3.0/tests/test_pagination.py +74 -0
  49. authpi_admin-0.3.0/uv.lock +483 -0
@@ -0,0 +1,51 @@
1
+ .DS_Store
2
+ node_modules
3
+ /build
4
+ .svelte-kit
5
+ /package
6
+ .wrangler
7
+ .env
8
+ .env.*
9
+ .dev.vars
10
+ !.env.example
11
+ !.env.e2e.example
12
+ vite.config.js.timestamp-*
13
+ vite.config.ts.timestamp-*
14
+ oracle.sql
15
+ dist
16
+ storybook-static
17
+ target
18
+ filter/
19
+ Cargo.lock
20
+ /sdk/core/
21
+ /sdk/oidc/
22
+ .stoplight
23
+ ratelimiter/
24
+ reproDo/
25
+ __pycache__/
26
+ .pytest_cache/
27
+ notebooks/
28
+ test-adyen/
29
+ stripe-authpi/
30
+ stripe-app/
31
+ secrets.json
32
+ .idea
33
+ .vscode
34
+ *.pem
35
+ *.key
36
+ *.crt
37
+ *.csr
38
+ *.env
39
+ output.txt
40
+ output.yaml
41
+ pnpm-lock.yaml
42
+ worker-configuration.d.ts
43
+
44
+ # Claude Code ephemeral artifacts
45
+ .claude/design-explorations/
46
+ .claude/plans/
47
+ .claude/worktrees/
48
+ .superpowers/
49
+ .worktrees/
50
+ docs/plans/
51
+ docs/superpowers/
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## [0.3.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.2.0...authpi-admin-v0.3.0) (2026-04-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * **sdks:** set custom User-Agent for SDK identification ([#213](https://github.com/arbfay/authpi/issues/213)) ([dec716c](https://github.com/arbfay/authpi/commit/dec716c99d877e99496f45c69f3625341bb2bc2e))
9
+
10
+ ## [0.2.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.1.0...authpi-admin-v0.2.0) (2026-04-13)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * All generated type interfaces now use snake_case field names. Consumers referencing camelCase fields (e.g., Client.issuerId) must update to snake_case (Client.issuer_id).
16
+
17
+ ### Features
18
+
19
+ * Admin SDK code generator + Python SDK (authpi-admin) ([#186](https://github.com/arbfay/authpi/issues/186)) ([3eb5055](https://github.com/arbfay/authpi/commit/3eb505579f34a49769e0b01eb59f6d571ad74571))
20
+ * SDK convergence — extend @authpi/admin, migrate console, security fixes ([#197](https://github.com/arbfay/authpi/issues/197)) ([3d4896f](https://github.com/arbfay/authpi/commit/3d4896fa60381542d99a66e394809d128bf6bcf0))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * **admin:** fix custom action paths, security hardening for TS and Python SDKs ([#189](https://github.com/arbfay/authpi/issues/189)) ([bf5e0b4](https://github.com/arbfay/authpi/commit/bf5e0b430a76173a1a1b4ff188095a96b337a74c))
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: authpi-admin
3
+ Version: 0.3.0
4
+ Summary: Official Python Admin SDK for AuthPI Core API
5
+ Project-URL: Homepage, https://authpi.com
6
+ Project-URL: Documentation, https://docs.authpi.com/sdk/python/admin
7
+ Project-URL: Repository, https://github.com/arbfay/authpi
8
+ Author-email: AuthPI <hello@authpi.com>
9
+ License: MIT
10
+ Keywords: admin,api,authentication,authorization,authpi,sdk
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Security
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
28
+ Requires-Dist: pytest-httpx>=0.34.0; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # authpi-admin
34
+
35
+ Official Python Admin SDK for the AuthPI Core API.
36
+
37
+ **Requirements:** Python 3.11+, async-only (`httpx` + `asyncio`)
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install authpi-admin
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ from authpi_admin import AuthPIAdmin
49
+
50
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
51
+ # List issuers
52
+ page = await admin.issuers.list(limit=10)
53
+ print(page.data)
54
+
55
+ # Scope into an issuer and manage users
56
+ users = await admin.issuer("iss_xxx").users.list()
57
+
58
+ # Auto-paginate
59
+ async for user in admin.issuer("iss_xxx").users.list_all():
60
+ print(user)
61
+
62
+ # Create a user
63
+ user = await admin.issuer("iss_xxx").users.create({
64
+ "email": "alice@example.com",
65
+ "display_name": "Alice",
66
+ })
67
+ ```
68
+
69
+ ## Authentication
70
+
71
+ ### API Key (default)
72
+
73
+ ```python
74
+ admin = AuthPIAdmin(api_key="key_xxx")
75
+ ```
76
+
77
+ ### Bearer Token
78
+
79
+ For server-side applications authenticating on behalf of a user session:
80
+
81
+ ```python
82
+ admin = AuthPIAdmin(
83
+ access_token="tok_xxx",
84
+ account_id="acc_xxx",
85
+ )
86
+ ```
87
+
88
+ With optional token refresh callback:
89
+
90
+ ```python
91
+ async def refresh():
92
+ new_tokens = await my_refresh_logic()
93
+ return {"access_token": new_tokens.access_token}
94
+
95
+ admin = AuthPIAdmin(
96
+ access_token="tok_xxx",
97
+ account_id="acc_xxx",
98
+ on_token_expired=refresh,
99
+ )
100
+ ```
101
+
102
+ When `on_token_expired` is provided, the SDK calls it on 401 responses and retries the request with the new token. Concurrent 401s are deduplicated — only one refresh runs at a time.
103
+
104
+ ## Scoped Client Pattern
105
+
106
+ The SDK mirrors the API's resource hierarchy. Navigate with chained accessors:
107
+
108
+ ```python
109
+ # Account-level resources
110
+ await admin.issuers.list()
111
+ await admin.webhooks.create({"url": "https://..."})
112
+ await admin.events.list(limit=50)
113
+
114
+ # Issuer scope
115
+ iss = admin.issuer("iss_xxx")
116
+ await iss.users.list()
117
+ await iss.agents.create({"name": "bot"})
118
+ await iss.clients.list()
119
+ await iss.organizations.list()
120
+
121
+ # User scope (nested under issuer)
122
+ usr = admin.issuer("iss_xxx").user("usr_xxx")
123
+ await usr.get()
124
+ await usr.sessions.list()
125
+ await usr.tokens.list()
126
+ await usr.trusted_devices.list()
127
+ await usr.verifiers.list()
128
+
129
+ # Webhook scope
130
+ wh = admin.webhook("wh_xxx")
131
+ await wh.get()
132
+ await wh.deliveries.list()
133
+ ```
134
+
135
+ ## Pagination
136
+
137
+ List endpoints return a `Page` with cursor-based pagination:
138
+
139
+ ```python
140
+ # Manual pagination
141
+ page = await admin.issuer("iss_xxx").users.list(limit=25)
142
+ print(page.data) # list[dict]
143
+ print(page.has_more) # bool
144
+ print(page.next_cursor) # str | None
145
+
146
+ # Fetch next page
147
+ if page.has_more:
148
+ next_page = await admin.issuer("iss_xxx").users.list(
149
+ limit=25, cursor=page.next_cursor
150
+ )
151
+
152
+ # Auto-pagination (yields individual items across all pages)
153
+ async for user in admin.issuer("iss_xxx").users.list_all():
154
+ print(user)
155
+ ```
156
+
157
+ ## Retries
158
+
159
+ Read-only requests (GET, HEAD, OPTIONS) are automatically retried on 429, 502, 503, and 504 responses with exponential backoff. The `Retry-After` header is respected when present.
160
+
161
+ ```python
162
+ # Default: retries enabled (3 attempts, 1s base delay, exponential backoff)
163
+ admin = AuthPIAdmin(api_key="key_xxx")
164
+
165
+ # Disable retries
166
+ admin = AuthPIAdmin(api_key="key_xxx", retries=False)
167
+
168
+ # Custom retry config
169
+ admin = AuthPIAdmin(
170
+ api_key="key_xxx",
171
+ retries={"limit": 5, "delay": 0.5, "backoff": "linear"},
172
+ )
173
+ ```
174
+
175
+ Mutations (POST, PATCH, DELETE) are never retried automatically. Use idempotency keys and handle retries explicitly for writes.
176
+
177
+ ## ETags & Optimistic Concurrency
178
+
179
+ GET responses include an `_etag` field. Pass it back on updates to prevent overwriting concurrent changes:
180
+
181
+ ```python
182
+ user = await admin.issuer("iss_xxx").user("usr_xxx").get()
183
+
184
+ # Conditional update — fails with PreconditionFailedError if modified
185
+ await admin.issuer("iss_xxx").users.update(
186
+ "usr_xxx",
187
+ {"display_name": "Bob"},
188
+ if_match=user.get("_etag"),
189
+ )
190
+ ```
191
+
192
+ ## Error Handling
193
+
194
+ The SDK maps HTTP status codes to specific error classes:
195
+
196
+ ```python
197
+ from authpi_admin import (
198
+ NotFoundError,
199
+ ValidationError,
200
+ AuthenticationError,
201
+ RateLimitError,
202
+ PreconditionFailedError,
203
+ )
204
+
205
+ try:
206
+ await admin.issuer("iss_xxx").user("usr_xxx").get()
207
+ except NotFoundError:
208
+ print("User not found")
209
+ except ValidationError as err:
210
+ print("Validation failed:", err.fields)
211
+ except RateLimitError as err:
212
+ print(f"Retry after {err.retry_after} seconds")
213
+ except AuthenticationError:
214
+ print("Invalid credentials")
215
+ ```
216
+
217
+ ### Error Hierarchy
218
+
219
+ | Error | Status | Extra Fields | Retryable |
220
+ |-------|--------|--------------|-----------|
221
+ | `ApiError` | — | `error`, `error_description`, `status_code`, `retryable`, `reference`, `raw_body` | — |
222
+ | `ValidationError` | 400, 422 | `fields` | No |
223
+ | `AuthenticationError` | 401 | — | No |
224
+ | `ForbiddenError` | 403 | — | No |
225
+ | `NotFoundError` | 404 | — | No |
226
+ | `ConflictError` | 409 | — | No |
227
+ | `PreconditionFailedError` | 412 | `current_etag` | No |
228
+ | `RateLimitError` | 429 | `retry_after` | Yes |
229
+ | `InternalServerError` | 500 | — | No |
230
+ | `BadGatewayError` | 502 | — | Yes |
231
+ | `ServiceUnavailableError` | 503 | — | Yes |
232
+ | `GatewayTimeoutError` | 504 | — | Yes |
233
+ | `UnexpectedError` | other | — | No |
234
+ | `ClosedClientError` | — | — | No |
235
+
236
+ ## Configuration
237
+
238
+ ```python
239
+ from authpi_admin import AuthPIAdmin
240
+
241
+ admin = AuthPIAdmin(
242
+ api_key="key_xxx", # or access_token + account_id
243
+ base_url="https://api.authpi.dev", # default
244
+ timeout=30.0, # default, in seconds
245
+ default_headers={"X-Custom": "value"}, # optional extra headers
246
+ retries=True, # default (or False, or dict)
247
+ )
248
+ ```
249
+
250
+ ### Custom httpx Client
251
+
252
+ Inject a pre-configured `httpx.AsyncClient` for advanced use cases (proxies, certificates, connection pooling):
253
+
254
+ ```python
255
+ import httpx
256
+ from authpi_admin import AuthPIAdmin
257
+
258
+ async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
259
+ admin = AuthPIAdmin(api_key="key_xxx", http_client=http)
260
+ await admin.issuers.list()
261
+ ```
262
+
263
+ ### Context Manager
264
+
265
+ The SDK supports async context managers for clean resource cleanup:
266
+
267
+ ```python
268
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
269
+ await admin.issuers.list()
270
+ # httpx client is closed automatically
271
+ ```
272
+
273
+ Or close manually:
274
+
275
+ ```python
276
+ admin = AuthPIAdmin(api_key="key_xxx")
277
+ try:
278
+ await admin.issuers.list()
279
+ finally:
280
+ await admin.close()
281
+ ```
282
+
283
+ ## License
284
+
285
+ MIT
@@ -0,0 +1,253 @@
1
+ # authpi-admin
2
+
3
+ Official Python Admin SDK for the AuthPI Core API.
4
+
5
+ **Requirements:** Python 3.11+, async-only (`httpx` + `asyncio`)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install authpi-admin
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from authpi_admin import AuthPIAdmin
17
+
18
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
19
+ # List issuers
20
+ page = await admin.issuers.list(limit=10)
21
+ print(page.data)
22
+
23
+ # Scope into an issuer and manage users
24
+ users = await admin.issuer("iss_xxx").users.list()
25
+
26
+ # Auto-paginate
27
+ async for user in admin.issuer("iss_xxx").users.list_all():
28
+ print(user)
29
+
30
+ # Create a user
31
+ user = await admin.issuer("iss_xxx").users.create({
32
+ "email": "alice@example.com",
33
+ "display_name": "Alice",
34
+ })
35
+ ```
36
+
37
+ ## Authentication
38
+
39
+ ### API Key (default)
40
+
41
+ ```python
42
+ admin = AuthPIAdmin(api_key="key_xxx")
43
+ ```
44
+
45
+ ### Bearer Token
46
+
47
+ For server-side applications authenticating on behalf of a user session:
48
+
49
+ ```python
50
+ admin = AuthPIAdmin(
51
+ access_token="tok_xxx",
52
+ account_id="acc_xxx",
53
+ )
54
+ ```
55
+
56
+ With optional token refresh callback:
57
+
58
+ ```python
59
+ async def refresh():
60
+ new_tokens = await my_refresh_logic()
61
+ return {"access_token": new_tokens.access_token}
62
+
63
+ admin = AuthPIAdmin(
64
+ access_token="tok_xxx",
65
+ account_id="acc_xxx",
66
+ on_token_expired=refresh,
67
+ )
68
+ ```
69
+
70
+ When `on_token_expired` is provided, the SDK calls it on 401 responses and retries the request with the new token. Concurrent 401s are deduplicated — only one refresh runs at a time.
71
+
72
+ ## Scoped Client Pattern
73
+
74
+ The SDK mirrors the API's resource hierarchy. Navigate with chained accessors:
75
+
76
+ ```python
77
+ # Account-level resources
78
+ await admin.issuers.list()
79
+ await admin.webhooks.create({"url": "https://..."})
80
+ await admin.events.list(limit=50)
81
+
82
+ # Issuer scope
83
+ iss = admin.issuer("iss_xxx")
84
+ await iss.users.list()
85
+ await iss.agents.create({"name": "bot"})
86
+ await iss.clients.list()
87
+ await iss.organizations.list()
88
+
89
+ # User scope (nested under issuer)
90
+ usr = admin.issuer("iss_xxx").user("usr_xxx")
91
+ await usr.get()
92
+ await usr.sessions.list()
93
+ await usr.tokens.list()
94
+ await usr.trusted_devices.list()
95
+ await usr.verifiers.list()
96
+
97
+ # Webhook scope
98
+ wh = admin.webhook("wh_xxx")
99
+ await wh.get()
100
+ await wh.deliveries.list()
101
+ ```
102
+
103
+ ## Pagination
104
+
105
+ List endpoints return a `Page` with cursor-based pagination:
106
+
107
+ ```python
108
+ # Manual pagination
109
+ page = await admin.issuer("iss_xxx").users.list(limit=25)
110
+ print(page.data) # list[dict]
111
+ print(page.has_more) # bool
112
+ print(page.next_cursor) # str | None
113
+
114
+ # Fetch next page
115
+ if page.has_more:
116
+ next_page = await admin.issuer("iss_xxx").users.list(
117
+ limit=25, cursor=page.next_cursor
118
+ )
119
+
120
+ # Auto-pagination (yields individual items across all pages)
121
+ async for user in admin.issuer("iss_xxx").users.list_all():
122
+ print(user)
123
+ ```
124
+
125
+ ## Retries
126
+
127
+ Read-only requests (GET, HEAD, OPTIONS) are automatically retried on 429, 502, 503, and 504 responses with exponential backoff. The `Retry-After` header is respected when present.
128
+
129
+ ```python
130
+ # Default: retries enabled (3 attempts, 1s base delay, exponential backoff)
131
+ admin = AuthPIAdmin(api_key="key_xxx")
132
+
133
+ # Disable retries
134
+ admin = AuthPIAdmin(api_key="key_xxx", retries=False)
135
+
136
+ # Custom retry config
137
+ admin = AuthPIAdmin(
138
+ api_key="key_xxx",
139
+ retries={"limit": 5, "delay": 0.5, "backoff": "linear"},
140
+ )
141
+ ```
142
+
143
+ Mutations (POST, PATCH, DELETE) are never retried automatically. Use idempotency keys and handle retries explicitly for writes.
144
+
145
+ ## ETags & Optimistic Concurrency
146
+
147
+ GET responses include an `_etag` field. Pass it back on updates to prevent overwriting concurrent changes:
148
+
149
+ ```python
150
+ user = await admin.issuer("iss_xxx").user("usr_xxx").get()
151
+
152
+ # Conditional update — fails with PreconditionFailedError if modified
153
+ await admin.issuer("iss_xxx").users.update(
154
+ "usr_xxx",
155
+ {"display_name": "Bob"},
156
+ if_match=user.get("_etag"),
157
+ )
158
+ ```
159
+
160
+ ## Error Handling
161
+
162
+ The SDK maps HTTP status codes to specific error classes:
163
+
164
+ ```python
165
+ from authpi_admin import (
166
+ NotFoundError,
167
+ ValidationError,
168
+ AuthenticationError,
169
+ RateLimitError,
170
+ PreconditionFailedError,
171
+ )
172
+
173
+ try:
174
+ await admin.issuer("iss_xxx").user("usr_xxx").get()
175
+ except NotFoundError:
176
+ print("User not found")
177
+ except ValidationError as err:
178
+ print("Validation failed:", err.fields)
179
+ except RateLimitError as err:
180
+ print(f"Retry after {err.retry_after} seconds")
181
+ except AuthenticationError:
182
+ print("Invalid credentials")
183
+ ```
184
+
185
+ ### Error Hierarchy
186
+
187
+ | Error | Status | Extra Fields | Retryable |
188
+ |-------|--------|--------------|-----------|
189
+ | `ApiError` | — | `error`, `error_description`, `status_code`, `retryable`, `reference`, `raw_body` | — |
190
+ | `ValidationError` | 400, 422 | `fields` | No |
191
+ | `AuthenticationError` | 401 | — | No |
192
+ | `ForbiddenError` | 403 | — | No |
193
+ | `NotFoundError` | 404 | — | No |
194
+ | `ConflictError` | 409 | — | No |
195
+ | `PreconditionFailedError` | 412 | `current_etag` | No |
196
+ | `RateLimitError` | 429 | `retry_after` | Yes |
197
+ | `InternalServerError` | 500 | — | No |
198
+ | `BadGatewayError` | 502 | — | Yes |
199
+ | `ServiceUnavailableError` | 503 | — | Yes |
200
+ | `GatewayTimeoutError` | 504 | — | Yes |
201
+ | `UnexpectedError` | other | — | No |
202
+ | `ClosedClientError` | — | — | No |
203
+
204
+ ## Configuration
205
+
206
+ ```python
207
+ from authpi_admin import AuthPIAdmin
208
+
209
+ admin = AuthPIAdmin(
210
+ api_key="key_xxx", # or access_token + account_id
211
+ base_url="https://api.authpi.dev", # default
212
+ timeout=30.0, # default, in seconds
213
+ default_headers={"X-Custom": "value"}, # optional extra headers
214
+ retries=True, # default (or False, or dict)
215
+ )
216
+ ```
217
+
218
+ ### Custom httpx Client
219
+
220
+ Inject a pre-configured `httpx.AsyncClient` for advanced use cases (proxies, certificates, connection pooling):
221
+
222
+ ```python
223
+ import httpx
224
+ from authpi_admin import AuthPIAdmin
225
+
226
+ async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
227
+ admin = AuthPIAdmin(api_key="key_xxx", http_client=http)
228
+ await admin.issuers.list()
229
+ ```
230
+
231
+ ### Context Manager
232
+
233
+ The SDK supports async context managers for clean resource cleanup:
234
+
235
+ ```python
236
+ async with AuthPIAdmin(api_key="key_xxx") as admin:
237
+ await admin.issuers.list()
238
+ # httpx client is closed automatically
239
+ ```
240
+
241
+ Or close manually:
242
+
243
+ ```python
244
+ admin = AuthPIAdmin(api_key="key_xxx")
245
+ try:
246
+ await admin.issuers.list()
247
+ finally:
248
+ await admin.close()
249
+ ```
250
+
251
+ ## License
252
+
253
+ MIT
@@ -0,0 +1,55 @@
1
+ """AuthPI Admin SDK — Official Python client for the AuthPI Core API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.3.0"
6
+
7
+ from authpi_admin.client import AuthPIAdmin
8
+ from authpi_admin.errors import (
9
+ ApiError,
10
+ AuthenticationError,
11
+ BadGatewayError,
12
+ ClosedClientError,
13
+ ConfigurationError,
14
+ ConflictError,
15
+ ForbiddenError,
16
+ GatewayTimeoutError,
17
+ InternalServerError,
18
+ NotFoundError,
19
+ PreconditionFailedError,
20
+ RateLimitError,
21
+ ServerError,
22
+ ServiceUnavailableError,
23
+ UnexpectedError,
24
+ ValidationError,
25
+ )
26
+ from authpi_admin.generated.scopes.issuer_scope import IssuerScope
27
+ from authpi_admin.generated.scopes.user_scope import UserScope
28
+ from authpi_admin.generated.scopes.agent_scope import AgentScope
29
+ from authpi_admin.generated.scopes.webhook_scope import WebhookScope
30
+ from authpi_admin.pagination import Page
31
+
32
+ __all__ = [
33
+ "AgentScope",
34
+ "ApiError",
35
+ "AuthPIAdmin",
36
+ "AuthenticationError",
37
+ "BadGatewayError",
38
+ "ClosedClientError",
39
+ "ConfigurationError",
40
+ "ConflictError",
41
+ "ForbiddenError",
42
+ "GatewayTimeoutError",
43
+ "InternalServerError",
44
+ "IssuerScope",
45
+ "NotFoundError",
46
+ "Page",
47
+ "PreconditionFailedError",
48
+ "RateLimitError",
49
+ "ServerError",
50
+ "ServiceUnavailableError",
51
+ "UnexpectedError",
52
+ "UserScope",
53
+ "ValidationError",
54
+ "WebhookScope",
55
+ ]
@@ -0,0 +1,5 @@
1
+ """SDK version — kept in sync with pyproject.toml via release-please."""
2
+
3
+ # x-release-please-start-version
4
+ SDK_VERSION = "0.3.0"
5
+ # x-release-please-end