authpi-admin 0.3.0__tar.gz → 0.7.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 (61) hide show
  1. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/.gitignore +9 -0
  2. authpi_admin-0.7.0/CHANGELOG.md +71 -0
  3. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/PKG-INFO +37 -11
  4. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/README.md +36 -10
  5. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/__init__.py +1 -1
  6. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/_version.py +1 -1
  7. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/client.py +33 -16
  8. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/__init__.py +13 -4
  9. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/models.py +288 -9
  10. authpi_admin-0.3.0/authpi_admin/generated/resources/api_keys.py → authpi_admin-0.7.0/authpi_admin/generated/resources/account_api_keys.py +88 -10
  11. authpi_admin-0.7.0/authpi_admin/generated/resources/account_tokens.py +85 -0
  12. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/accounts.py +8 -53
  13. authpi_admin-0.3.0/authpi_admin/generated/resources/verifiers.py → authpi_admin-0.7.0/authpi_admin/generated/resources/agent_verifiers.py +6 -6
  14. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/agents.py +11 -8
  15. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/approvals.py +3 -3
  16. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/auth_methods.py +11 -8
  17. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/clients.py +5 -5
  18. authpi_admin-0.7.0/authpi_admin/generated/resources/credits.py +100 -0
  19. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/deliveries.py +1 -1
  20. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/domains.py +12 -9
  21. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/events.py +53 -2
  22. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/groups.py +14 -14
  23. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/invitations.py +15 -14
  24. authpi_admin-0.3.0/authpi_admin/generated/resources/sessions.py → authpi_admin-0.7.0/authpi_admin/generated/resources/issuer_sessions.py +8 -8
  25. authpi_admin-0.7.0/authpi_admin/generated/resources/issuer_tokens.py +46 -0
  26. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/issuers.py +11 -8
  27. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/members.py +12 -11
  28. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/notes.py +61 -4
  29. authpi_admin-0.3.0/authpi_admin/generated/resources/trusted_devices.py → authpi_admin-0.7.0/authpi_admin/generated/resources/organization_api_keys.py +22 -30
  30. authpi_admin-0.7.0/authpi_admin/generated/resources/organizations.py +182 -0
  31. authpi_admin-0.7.0/authpi_admin/generated/resources/payment_methods.py +95 -0
  32. authpi_admin-0.7.0/authpi_admin/generated/resources/sso.py +134 -0
  33. authpi_admin-0.7.0/authpi_admin/generated/resources/trusted_devices.py +133 -0
  34. authpi_admin-0.7.0/authpi_admin/generated/resources/user_sessions.py +62 -0
  35. authpi_admin-0.3.0/authpi_admin/generated/resources/tokens.py → authpi_admin-0.7.0/authpi_admin/generated/resources/user_tokens.py +6 -6
  36. authpi_admin-0.3.0/authpi_admin/generated/resources/users.py → authpi_admin-0.7.0/authpi_admin/generated/resources/user_verifiers.py +82 -63
  37. authpi_admin-0.7.0/authpi_admin/generated/resources/users.py +162 -0
  38. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/webhooks.py +4 -4
  39. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/scopes/agent_scope.py +6 -6
  40. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/scopes/issuer_scope.py +16 -35
  41. authpi_admin-0.7.0/authpi_admin/generated/scopes/organization_scope.py +108 -0
  42. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/scopes/user_scope.py +12 -12
  43. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/scopes/webhook_scope.py +3 -3
  44. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/http_client.py +94 -15
  45. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/pyproject.toml +1 -1
  46. authpi_admin-0.7.0/tests/test_client.py +176 -0
  47. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/tests/test_http_client.py +44 -18
  48. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/tests/test_integration.py +55 -31
  49. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/uv.lock +240 -238
  50. authpi_admin-0.3.0/CHANGELOG.md +0 -25
  51. authpi_admin-0.3.0/authpi_admin/generated/resources/organizations.py +0 -244
  52. authpi_admin-0.3.0/tests/test_client.py +0 -90
  53. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/errors.py +0 -0
  54. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/resources/__init__.py +0 -0
  55. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/generated/scopes/__init__.py +0 -0
  56. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/pagination.py +0 -0
  57. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/py.typed +0 -0
  58. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/authpi_admin/user_agent.py +0 -0
  59. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/tests/__init__.py +0 -0
  60. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/tests/test_errors.py +0 -0
  61. {authpi_admin-0.3.0 → authpi_admin-0.7.0}/tests/test_pagination.py +0 -0
@@ -13,6 +13,7 @@ vite.config.js.timestamp-*
13
13
  vite.config.ts.timestamp-*
14
14
  oracle.sql
15
15
  dist
16
+ dist-templates/
16
17
  storybook-static
17
18
  target
18
19
  filter/
@@ -29,6 +30,7 @@ test-adyen/
29
30
  stripe-authpi/
30
31
  stripe-app/
31
32
  secrets.json
33
+ *.secrets.json
32
34
  .idea
33
35
  .vscode
34
36
  *.pem
@@ -49,3 +51,10 @@ worker-configuration.d.ts
49
51
  .worktrees/
50
52
  docs/plans/
51
53
  docs/superpowers/
54
+ docs/.obsidian/
55
+
56
+ # Operator-rendered ops-db bootstrap files — carry environment-specific
57
+ # captured `agt_*` IDs from the Step 3 bootstrap. The .template stays in
58
+ # git as the canonical structure; rendered copies stay local.
59
+ d1-databases/ops-db/0005_bootstrap_capability_matrix.sql
60
+ d1-databases/ops-db/0005_bootstrap_capability_matrix_prod.sql
@@ -0,0 +1,71 @@
1
+ # Changelog
2
+
3
+ ## [0.7.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.6.0...authpi-admin-v0.7.0) (2026-06-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * GET /v1/me — caller identity endpoint (AUT-163) ([#286](https://github.com/arbfay/authpi/issues/286)) ([b9f35dc](https://github.com/arbfay/authpi/commit/b9f35dc2fd8cca77cdd2079b240ce28dc11d35a8))
9
+
10
+ ## [0.6.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.4.0...authpi-admin-v0.6.0) (2026-06-11)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * **admin-py:** collision-split class renames (see admin-ts) and issuer-scope org-subresource accessors moved to the organization scope; the removed accessors 404'd on every call, so no working integration is affected.
16
+ * **admin-ts:** cross-scope name collisions split generated classes (ApiKeysResource -> AccountApiKeysResource, TokensResource -> AccountTokensResource, SessionsResource -> IssuerSessionsResource / UserSessionsResource, VerifiersResource -> AgentVerifiersResource / UserVerifiersResource), and the issuer-scope groups/invitations/ members/domains accessors moved to the new organization scope. The removed accessors produced 404s on every call, so no working integration is affected.
17
+
18
+ ### Features
19
+
20
+ * **admin-py:** regenerate from corrected spec — org scope, restored endpoints, credits ([2cd96b5](https://github.com/arbfay/authpi/commit/2cd96b569ab9ddff8589fd8e786a16052af4c7e5))
21
+ * **admin-ts:** regenerate from corrected spec — org scope, restored endpoints, credits ([3932b60](https://github.com/arbfay/authpi/commit/3932b609116f059dff36a73f9a5378c21d69eb3d))
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * **generators:** action methods carry query params and real response types ([0f515ec](https://github.com/arbfay/authpi/commit/0f515ecc1ce737f62e2826ff3106b97c35a6ce2f))
27
+
28
+ ## [0.4.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.3.1...authpi-admin-v0.4.0) (2026-06-11)
29
+
30
+
31
+ ### ⚠ BREAKING CHANGES
32
+
33
+ * **admin-py:** `account_id` is now required for both auth modes. The api_key-without-account_id form never produced a successful request.
34
+ * **admin-py:** `api_key` changed from `str` to `tuple[str, str]`. The previous form never authenticated successfully, so no working integration is affected.
35
+
36
+ ### Bug Fixes
37
+
38
+ * **admin-py:** default base_url to the production API ([4351942](https://github.com/arbfay/authpi/commit/4351942f3c40d75b24e079e1d83553e6f58a3303))
39
+ * **admin-py:** require account_id — the API has no accounts/me alias ([58cf3a2](https://github.com/arbfay/authpi/commit/58cf3a2a1af402f7b9e20ceadd84e6015957f000))
40
+ * **admin-py:** send API keys as HTTP Basic id:secret pair ([aee64f7](https://github.com/arbfay/authpi/commit/aee64f777abb18ecb4578c178cf55a4c72abb046))
41
+
42
+ ## [0.3.1](https://github.com/arbfay/authpi/compare/authpi-admin-v0.3.0...authpi-admin-v0.3.1) (2026-06-10)
43
+
44
+
45
+ ### Bug Fixes
46
+
47
+ * **admin-py:** unwrap the single-resource data envelope in generated methods ([d63ee44](https://github.com/arbfay/authpi/commit/d63ee44d9db64e46dbfbfc5da66c4a1aaeacf609))
48
+
49
+ ## [0.3.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.2.0...authpi-admin-v0.3.0) (2026-04-17)
50
+
51
+
52
+ ### Features
53
+
54
+ * **sdks:** set custom User-Agent for SDK identification ([#213](https://github.com/arbfay/authpi/issues/213)) ([dec716c](https://github.com/arbfay/authpi/commit/dec716c99d877e99496f45c69f3625341bb2bc2e))
55
+
56
+ ## [0.2.0](https://github.com/arbfay/authpi/compare/authpi-admin-v0.1.0...authpi-admin-v0.2.0) (2026-04-13)
57
+
58
+
59
+ ### ⚠ BREAKING CHANGES
60
+
61
+ * 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).
62
+
63
+ ### Features
64
+
65
+ * Admin SDK code generator + Python SDK (authpi-admin) ([#186](https://github.com/arbfay/authpi/issues/186)) ([3eb5055](https://github.com/arbfay/authpi/commit/3eb505579f34a49769e0b01eb59f6d571ad74571))
66
+ * 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))
67
+
68
+
69
+ ### Bug Fixes
70
+
71
+ * **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))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: authpi-admin
3
- Version: 0.3.0
3
+ Version: 0.7.0
4
4
  Summary: Official Python Admin SDK for AuthPI Core API
5
5
  Project-URL: Homepage, https://authpi.com
6
6
  Project-URL: Documentation, https://docs.authpi.com/sdk/python/admin
@@ -47,7 +47,7 @@ pip install authpi-admin
47
47
  ```python
48
48
  from authpi_admin import AuthPIAdmin
49
49
 
50
- async with AuthPIAdmin(api_key="key_xxx") as admin:
50
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx") as admin:
51
51
  # List issuers
52
52
  page = await admin.issuers.list(limit=10)
53
53
  print(page.data)
@@ -70,8 +70,10 @@ async with AuthPIAdmin(api_key="key_xxx") as admin:
70
70
 
71
71
  ### API Key (default)
72
72
 
73
+ API keys are issued as an **id + secret pair** — both parts are shown once when you create the key in the dashboard. The SDK sends them as HTTP Basic credentials (`key_id:key_secret`):
74
+
73
75
  ```python
74
- admin = AuthPIAdmin(api_key="key_xxx")
76
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
75
77
  ```
76
78
 
77
79
  ### Bearer Token
@@ -101,6 +103,24 @@ admin = AuthPIAdmin(
101
103
 
102
104
  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
105
 
106
+ ### Account resolution
107
+
108
+ `account_id` is optional. When omitted, the SDK resolves it once via `GET /v1/me` on the first request and caches it — an API key always maps to exactly one account:
109
+
110
+ ```python
111
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret")) as admin:
112
+ issuers = await admin.issuers.list() # resolves the account transparently
113
+ ```
114
+
115
+ If the credential can act on zero or multiple accounts (possible with user bearer tokens), the SDK raises a `ConfigurationError` naming the choices — pass `account_id` explicitly in that case.
116
+
117
+ You can also ask directly who the API considers you to be:
118
+
119
+ ```python
120
+ me = await admin.whoami()
121
+ # {"type": "api_key", "key_id": "key_...", "issuer_id": "i_...", "accounts": [{"account_id": ..., "org_id": ..., "scopes": [...]}]}
122
+ ```
123
+
104
124
  ## Scoped Client Pattern
105
125
 
106
126
  The SDK mirrors the API's resource hierarchy. Navigate with chained accessors:
@@ -119,6 +139,10 @@ await iss.clients.list()
119
139
  await iss.organizations.list()
120
140
 
121
141
  # User scope (nested under issuer)
142
+ org = admin.issuer("iss_xxx").organization("org_xxx")
143
+ await org.members.list()
144
+ await org.sso.add_domain(domain="acme.com")
145
+
122
146
  usr = admin.issuer("iss_xxx").user("usr_xxx")
123
147
  await usr.get()
124
148
  await usr.sessions.list()
@@ -160,14 +184,15 @@ Read-only requests (GET, HEAD, OPTIONS) are automatically retried on 429, 502, 5
160
184
 
161
185
  ```python
162
186
  # Default: retries enabled (3 attempts, 1s base delay, exponential backoff)
163
- admin = AuthPIAdmin(api_key="key_xxx")
187
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
164
188
 
165
189
  # Disable retries
166
- admin = AuthPIAdmin(api_key="key_xxx", retries=False)
190
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), retries=False)
167
191
 
168
192
  # Custom retry config
169
193
  admin = AuthPIAdmin(
170
- api_key="key_xxx",
194
+ api_key=("key_xxx", "your_key_secret"),
195
+ account_id="acc_xxx",
171
196
  retries={"limit": 5, "delay": 0.5, "backoff": "linear"},
172
197
  )
173
198
  ```
@@ -239,8 +264,9 @@ except AuthenticationError:
239
264
  from authpi_admin import AuthPIAdmin
240
265
 
241
266
  admin = AuthPIAdmin(
242
- api_key="key_xxx", # or access_token + account_id
243
- base_url="https://api.authpi.dev", # default
267
+ api_key=("key_xxx", "your_key_secret"), # or access_token instead
268
+ account_id="acc_xxx", # optional — resolved via GET /v1/me when omitted
269
+ base_url="https://api.authpi.com", # default
244
270
  timeout=30.0, # default, in seconds
245
271
  default_headers={"X-Custom": "value"}, # optional extra headers
246
272
  retries=True, # default (or False, or dict)
@@ -256,7 +282,7 @@ import httpx
256
282
  from authpi_admin import AuthPIAdmin
257
283
 
258
284
  async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
259
- admin = AuthPIAdmin(api_key="key_xxx", http_client=http)
285
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), http_client=http)
260
286
  await admin.issuers.list()
261
287
  ```
262
288
 
@@ -265,7 +291,7 @@ async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
265
291
  The SDK supports async context managers for clean resource cleanup:
266
292
 
267
293
  ```python
268
- async with AuthPIAdmin(api_key="key_xxx") as admin:
294
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx") as admin:
269
295
  await admin.issuers.list()
270
296
  # httpx client is closed automatically
271
297
  ```
@@ -273,7 +299,7 @@ async with AuthPIAdmin(api_key="key_xxx") as admin:
273
299
  Or close manually:
274
300
 
275
301
  ```python
276
- admin = AuthPIAdmin(api_key="key_xxx")
302
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
277
303
  try:
278
304
  await admin.issuers.list()
279
305
  finally:
@@ -15,7 +15,7 @@ pip install authpi-admin
15
15
  ```python
16
16
  from authpi_admin import AuthPIAdmin
17
17
 
18
- async with AuthPIAdmin(api_key="key_xxx") as admin:
18
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx") as admin:
19
19
  # List issuers
20
20
  page = await admin.issuers.list(limit=10)
21
21
  print(page.data)
@@ -38,8 +38,10 @@ async with AuthPIAdmin(api_key="key_xxx") as admin:
38
38
 
39
39
  ### API Key (default)
40
40
 
41
+ API keys are issued as an **id + secret pair** — both parts are shown once when you create the key in the dashboard. The SDK sends them as HTTP Basic credentials (`key_id:key_secret`):
42
+
41
43
  ```python
42
- admin = AuthPIAdmin(api_key="key_xxx")
44
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
43
45
  ```
44
46
 
45
47
  ### Bearer Token
@@ -69,6 +71,24 @@ admin = AuthPIAdmin(
69
71
 
70
72
  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
73
 
74
+ ### Account resolution
75
+
76
+ `account_id` is optional. When omitted, the SDK resolves it once via `GET /v1/me` on the first request and caches it — an API key always maps to exactly one account:
77
+
78
+ ```python
79
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret")) as admin:
80
+ issuers = await admin.issuers.list() # resolves the account transparently
81
+ ```
82
+
83
+ If the credential can act on zero or multiple accounts (possible with user bearer tokens), the SDK raises a `ConfigurationError` naming the choices — pass `account_id` explicitly in that case.
84
+
85
+ You can also ask directly who the API considers you to be:
86
+
87
+ ```python
88
+ me = await admin.whoami()
89
+ # {"type": "api_key", "key_id": "key_...", "issuer_id": "i_...", "accounts": [{"account_id": ..., "org_id": ..., "scopes": [...]}]}
90
+ ```
91
+
72
92
  ## Scoped Client Pattern
73
93
 
74
94
  The SDK mirrors the API's resource hierarchy. Navigate with chained accessors:
@@ -87,6 +107,10 @@ await iss.clients.list()
87
107
  await iss.organizations.list()
88
108
 
89
109
  # User scope (nested under issuer)
110
+ org = admin.issuer("iss_xxx").organization("org_xxx")
111
+ await org.members.list()
112
+ await org.sso.add_domain(domain="acme.com")
113
+
90
114
  usr = admin.issuer("iss_xxx").user("usr_xxx")
91
115
  await usr.get()
92
116
  await usr.sessions.list()
@@ -128,14 +152,15 @@ Read-only requests (GET, HEAD, OPTIONS) are automatically retried on 429, 502, 5
128
152
 
129
153
  ```python
130
154
  # Default: retries enabled (3 attempts, 1s base delay, exponential backoff)
131
- admin = AuthPIAdmin(api_key="key_xxx")
155
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
132
156
 
133
157
  # Disable retries
134
- admin = AuthPIAdmin(api_key="key_xxx", retries=False)
158
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), retries=False)
135
159
 
136
160
  # Custom retry config
137
161
  admin = AuthPIAdmin(
138
- api_key="key_xxx",
162
+ api_key=("key_xxx", "your_key_secret"),
163
+ account_id="acc_xxx",
139
164
  retries={"limit": 5, "delay": 0.5, "backoff": "linear"},
140
165
  )
141
166
  ```
@@ -207,8 +232,9 @@ except AuthenticationError:
207
232
  from authpi_admin import AuthPIAdmin
208
233
 
209
234
  admin = AuthPIAdmin(
210
- api_key="key_xxx", # or access_token + account_id
211
- base_url="https://api.authpi.dev", # default
235
+ api_key=("key_xxx", "your_key_secret"), # or access_token instead
236
+ account_id="acc_xxx", # optional — resolved via GET /v1/me when omitted
237
+ base_url="https://api.authpi.com", # default
212
238
  timeout=30.0, # default, in seconds
213
239
  default_headers={"X-Custom": "value"}, # optional extra headers
214
240
  retries=True, # default (or False, or dict)
@@ -224,7 +250,7 @@ import httpx
224
250
  from authpi_admin import AuthPIAdmin
225
251
 
226
252
  async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
227
- admin = AuthPIAdmin(api_key="key_xxx", http_client=http)
253
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), http_client=http)
228
254
  await admin.issuers.list()
229
255
  ```
230
256
 
@@ -233,7 +259,7 @@ async with httpx.AsyncClient(proxies="http://proxy:8080") as http:
233
259
  The SDK supports async context managers for clean resource cleanup:
234
260
 
235
261
  ```python
236
- async with AuthPIAdmin(api_key="key_xxx") as admin:
262
+ async with AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx") as admin:
237
263
  await admin.issuers.list()
238
264
  # httpx client is closed automatically
239
265
  ```
@@ -241,7 +267,7 @@ async with AuthPIAdmin(api_key="key_xxx") as admin:
241
267
  Or close manually:
242
268
 
243
269
  ```python
244
- admin = AuthPIAdmin(api_key="key_xxx")
270
+ admin = AuthPIAdmin(api_key=("key_xxx", "your_key_secret"), account_id="acc_xxx")
245
271
  try:
246
272
  await admin.issuers.list()
247
273
  finally:
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.3.0"
5
+ __version__ = "0.7.0"
6
6
 
7
7
  from authpi_admin.client import AuthPIAdmin
8
8
  from authpi_admin.errors import (
@@ -1,5 +1,5 @@
1
1
  """SDK version — kept in sync with pyproject.toml via release-please."""
2
2
 
3
3
  # x-release-please-start-version
4
- SDK_VERSION = "0.3.0"
4
+ SDK_VERSION = "0.7.0"
5
5
  # x-release-please-end
@@ -2,23 +2,25 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import Awaitable, Callable
5
6
  from functools import cached_property
6
- from typing import TYPE_CHECKING, Any, Awaitable, Callable
7
+ from typing import TYPE_CHECKING, Any
7
8
 
8
9
  import httpx
9
10
 
10
11
  from authpi_admin.errors import ConfigurationError
11
- from authpi_admin.http_client import HttpClient
12
+ from authpi_admin.generated.resources.account_api_keys import AccountApiKeysResource
13
+ from authpi_admin.generated.resources.account_tokens import AccountTokensResource
12
14
  from authpi_admin.generated.resources.accounts import AccountsResource
13
- from authpi_admin.generated.resources.api_keys import ApiKeysResource
15
+ from authpi_admin.generated.resources.credits import CreditsResource
14
16
  from authpi_admin.generated.resources.domains import DomainsResource
15
17
  from authpi_admin.generated.resources.events import EventsResource
16
18
  from authpi_admin.generated.resources.issuers import IssuersResource
17
19
  from authpi_admin.generated.resources.notes import NotesResource
18
- from authpi_admin.generated.resources.tokens import TokensResource
19
20
  from authpi_admin.generated.resources.webhooks import WebhooksResource
20
21
  from authpi_admin.generated.scopes.issuer_scope import IssuerScope
21
22
  from authpi_admin.generated.scopes.webhook_scope import WebhookScope
23
+ from authpi_admin.http_client import UNRESOLVED_ACCOUNT_ID, HttpClient
22
24
 
23
25
  if TYPE_CHECKING:
24
26
  from types import TracebackType
@@ -27,8 +29,11 @@ if TYPE_CHECKING:
27
29
  class AuthPIAdmin:
28
30
  """Entry-point client for the AuthPI Core API.
29
31
 
30
- Usage with API key:
31
- async with AuthPIAdmin(api_key="key_xxx") as admin:
32
+ Usage with API key (id + secret pair, sent as HTTP Basic):
33
+ async with AuthPIAdmin(
34
+ api_key=("key_xxx", "your_key_secret"),
35
+ account_id="acc_xxx",
36
+ ) as admin:
32
37
  users = await admin.issuer("iss_xxx").users.list()
33
38
 
34
39
  Usage with bearer token:
@@ -42,11 +47,11 @@ class AuthPIAdmin:
42
47
  def __init__(
43
48
  self,
44
49
  *,
45
- api_key: str | None = None,
50
+ api_key: tuple[str, str] | None = None,
46
51
  access_token: str | None = None,
47
52
  on_token_expired: Callable[[], Awaitable[dict[str, str]]] | None = None,
48
53
  account_id: str | None = None,
49
- base_url: str = "https://api.authpi.dev",
54
+ base_url: str = "https://api.authpi.com",
50
55
  http_client: httpx.AsyncClient | None = None,
51
56
  timeout: float = 30.0,
52
57
  default_headers: dict[str, str] | None = None,
@@ -56,10 +61,7 @@ class AuthPIAdmin:
56
61
  raise ConfigurationError("Either api_key or access_token is required")
57
62
  if api_key and access_token:
58
63
  raise ConfigurationError("Provide either api_key or access_token, not both")
59
- if access_token and not account_id:
60
- raise ConfigurationError("account_id is required when using access_token")
61
64
 
62
- resolved_account_id = account_id or "me"
63
65
  self._http = HttpClient(
64
66
  base_url=base_url,
65
67
  api_key=api_key,
@@ -70,13 +72,23 @@ class AuthPIAdmin:
70
72
  default_headers=default_headers,
71
73
  retries=retries,
72
74
  )
73
- self._base_path = f"/v1/accounts/{resolved_account_id}"
75
+ # Without an explicit account_id, paths carry a placeholder that the
76
+ # HttpClient substitutes at request time after resolving GET /v1/me once.
77
+ self._base_path = f"/v1/accounts/{account_id or UNRESOLVED_ACCOUNT_ID}"
74
78
 
75
79
  @property
76
80
  def http(self) -> HttpClient:
77
81
  """The underlying HTTP client (for advanced use)."""
78
82
  return self._http
79
83
 
84
+ async def whoami(self) -> dict[str, Any]:
85
+ """Who does the Core API consider this credential to be?
86
+
87
+ Returns the credential type and the verified accounts it can act on
88
+ (``GET /v1/me``).
89
+ """
90
+ return await self._http.whoami()
91
+
80
92
  # --- Account-level resource accessors ---
81
93
 
82
94
  @cached_property
@@ -85,9 +97,14 @@ class AuthPIAdmin:
85
97
  return AccountsResource(self._http, "/v1/accounts")
86
98
 
87
99
  @cached_property
88
- def api_keys(self) -> ApiKeysResource:
100
+ def api_keys(self) -> AccountApiKeysResource:
89
101
  """Manage account-level API keys."""
90
- return ApiKeysResource(self._http, f"{self._base_path}/api-keys")
102
+ return AccountApiKeysResource(self._http, f"{self._base_path}/api-keys")
103
+
104
+ @cached_property
105
+ def credits(self) -> CreditsResource:
106
+ """Account credit balance, ledger, and top-ups."""
107
+ return CreditsResource(self._http, f"{self._base_path}/credits")
91
108
 
92
109
  @cached_property
93
110
  def domains(self) -> DomainsResource:
@@ -110,9 +127,9 @@ class AuthPIAdmin:
110
127
  return NotesResource(self._http, f"{self._base_path}/notes")
111
128
 
112
129
  @cached_property
113
- def tokens(self) -> TokensResource:
130
+ def tokens(self) -> AccountTokensResource:
114
131
  """Manage account-level tokens."""
115
- return TokensResource(self._http, f"{self._base_path}/tokens")
132
+ return AccountTokensResource(self._http, f"{self._base_path}/tokens")
116
133
 
117
134
  @cached_property
118
135
  def webhooks(self) -> WebhooksResource:
@@ -2,27 +2,36 @@
2
2
 
3
3
  from .models import * # noqa: F401,F403
4
4
  from .resources.accounts import AccountsResource # noqa: F401
5
- from .resources.api_keys import ApiKeysResource # noqa: F401
5
+ from .resources.account_api_keys import AccountApiKeysResource # noqa: F401
6
+ from .resources.credits import CreditsResource # noqa: F401
6
7
  from .resources.domains import DomainsResource # noqa: F401
7
8
  from .resources.events import EventsResource # noqa: F401
8
9
  from .resources.issuers import IssuersResource # noqa: F401
9
10
  from .resources.agents import AgentsResource # noqa: F401
10
- from .resources.verifiers import VerifiersResource # noqa: F401
11
+ from .resources.agent_verifiers import AgentVerifiersResource # noqa: F401
11
12
  from .resources.approvals import ApprovalsResource # noqa: F401
12
13
  from .resources.auth_methods import AuthMethodsResource # noqa: F401
13
14
  from .resources.clients import ClientsResource # noqa: F401
14
15
  from .resources.organizations import OrganizationsResource # noqa: F401
16
+ from .resources.organization_api_keys import OrganizationApiKeysResource # noqa: F401
15
17
  from .resources.groups import GroupsResource # noqa: F401
16
18
  from .resources.invitations import InvitationsResource # noqa: F401
17
19
  from .resources.members import MembersResource # noqa: F401
18
- from .resources.sessions import SessionsResource # noqa: F401
20
+ from .resources.sso import SsoResource # noqa: F401
21
+ from .resources.issuer_sessions import IssuerSessionsResource # noqa: F401
22
+ from .resources.issuer_tokens import IssuerTokensResource # noqa: F401
19
23
  from .resources.users import UsersResource # noqa: F401
20
- from .resources.tokens import TokensResource # noqa: F401
24
+ from .resources.user_sessions import UserSessionsResource # noqa: F401
25
+ from .resources.user_tokens import UserTokensResource # noqa: F401
21
26
  from .resources.trusted_devices import TrustedDevicesResource # noqa: F401
27
+ from .resources.user_verifiers import UserVerifiersResource # noqa: F401
22
28
  from .resources.notes import NotesResource # noqa: F401
29
+ from .resources.payment_methods import PaymentMethodsResource # noqa: F401
30
+ from .resources.account_tokens import AccountTokensResource # noqa: F401
23
31
  from .resources.webhooks import WebhooksResource # noqa: F401
24
32
  from .resources.deliveries import DeliveriesResource # noqa: F401
25
33
  from .scopes.issuer_scope import IssuerScope # noqa: F401
26
34
  from .scopes.agent_scope import AgentScope # noqa: F401
35
+ from .scopes.organization_scope import OrganizationScope # noqa: F401
27
36
  from .scopes.user_scope import UserScope # noqa: F401
28
37
  from .scopes.webhook_scope import WebhookScope # noqa: F401