dominusnode 1.3.0__tar.gz → 1.5.2__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 (51) hide show
  1. {dominusnode-1.3.0 → dominusnode-1.5.2}/PKG-INFO +1 -1
  2. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/constants.py +1 -1
  3. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode.egg-info/PKG-INFO +1 -1
  4. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode.egg-info/SOURCES.txt +6 -0
  5. {dominusnode-1.3.0 → dominusnode-1.5.2}/pyproject.toml +1 -1
  6. dominusnode-1.5.2/tests/test_agentic_wallet.py +427 -0
  7. dominusnode-1.5.2/tests/test_api_keys.py +223 -0
  8. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_client.py +217 -9
  9. dominusnode-1.5.2/tests/test_http_client.py +258 -0
  10. dominusnode-1.5.2/tests/test_proxy.py +431 -0
  11. dominusnode-1.5.2/tests/test_sessions.py +123 -0
  12. dominusnode-1.5.2/tests/test_teams.py +509 -0
  13. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_usage.py +171 -5
  14. dominusnode-1.5.2/tests/test_users.py +527 -0
  15. dominusnode-1.5.2/tests/test_wallet.py +377 -0
  16. dominusnode-1.3.0/tests/test_proxy.py +0 -168
  17. dominusnode-1.3.0/tests/test_wallet.py +0 -155
  18. {dominusnode-1.3.0 → dominusnode-1.5.2}/LICENSE +0 -0
  19. {dominusnode-1.3.0 → dominusnode-1.5.2}/README.md +0 -0
  20. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/__init__.py +0 -0
  21. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/admin.py +0 -0
  22. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/agent_wallet.py +0 -0
  23. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/auth.py +0 -0
  24. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/client.py +0 -0
  25. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/errors.py +0 -0
  26. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/http_client.py +0 -0
  27. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/keys.py +0 -0
  28. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/mpp.py +0 -0
  29. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/plans.py +0 -0
  30. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/proxy.py +0 -0
  31. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/py.typed +0 -0
  32. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/sessions.py +0 -0
  33. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/slots.py +0 -0
  34. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/teams.py +0 -0
  35. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/token_manager.py +0 -0
  36. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/types.py +0 -0
  37. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/usage.py +0 -0
  38. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/wallet.py +0 -0
  39. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/wallet_auth.py +0 -0
  40. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode/x402.py +0 -0
  41. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode.egg-info/dependency_links.txt +0 -0
  42. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode.egg-info/requires.txt +0 -0
  43. {dominusnode-1.3.0 → dominusnode-1.5.2}/dominusnode.egg-info/top_level.txt +0 -0
  44. {dominusnode-1.3.0 → dominusnode-1.5.2}/setup.cfg +0 -0
  45. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_admin.py +0 -0
  46. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_auth.py +0 -0
  47. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_errors.py +0 -0
  48. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_keys.py +0 -0
  49. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_token_manager.py +0 -0
  50. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_wallet_auth.py +0 -0
  51. {dominusnode-1.3.0 → dominusnode-1.5.2}/tests/test_x402.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominusnode
3
- Version: 1.3.0
3
+ Version: 1.5.2
4
4
  Summary: Official Dominus Node SDK for Python
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -1,6 +1,6 @@
1
1
  """SDK constants."""
2
2
 
3
- SDK_VERSION = "1.0.0"
3
+ SDK_VERSION = "1.5.2"
4
4
  USER_AGENT = f"dominusnode-sdk-python/{SDK_VERSION}"
5
5
 
6
6
  DEFAULT_BASE_URL = "https://api.dominusnode.com"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominusnode
3
- Version: 1.3.0
3
+ Version: 1.5.2
4
4
  Summary: Official Dominus Node SDK for Python
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -29,13 +29,19 @@ dominusnode.egg-info/dependency_links.txt
29
29
  dominusnode.egg-info/requires.txt
30
30
  dominusnode.egg-info/top_level.txt
31
31
  tests/test_admin.py
32
+ tests/test_agentic_wallet.py
33
+ tests/test_api_keys.py
32
34
  tests/test_auth.py
33
35
  tests/test_client.py
34
36
  tests/test_errors.py
37
+ tests/test_http_client.py
35
38
  tests/test_keys.py
36
39
  tests/test_proxy.py
40
+ tests/test_sessions.py
41
+ tests/test_teams.py
37
42
  tests/test_token_manager.py
38
43
  tests/test_usage.py
44
+ tests/test_users.py
39
45
  tests/test_wallet.py
40
46
  tests/test_wallet_auth.py
41
47
  tests/test_x402.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dominusnode"
7
- version = "1.3.0"
7
+ version = "1.5.2"
8
8
  description = "Official Dominus Node SDK for Python"
9
9
  requires-python = ">=3.9"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,427 @@
1
+ """Tests for AgenticWalletResource -- create, list, get, fund, freeze/unfreeze,
2
+ delete, update policy, transactions, input validation, and error handling."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from unittest.mock import MagicMock
7
+
8
+ import pytest
9
+
10
+ from dominusnode.agent_wallet import AgenticWalletResource
11
+ from dominusnode.errors import (
12
+ AuthenticationError,
13
+ AuthorizationError,
14
+ NotFoundError,
15
+ ServerError,
16
+ ValidationError,
17
+ )
18
+ from dominusnode.types import AgenticWallet, AgenticWalletTransaction
19
+
20
+
21
+ class TestAgenticWalletResourceCreate:
22
+ """Tests for AgenticWalletResource.create()."""
23
+
24
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
25
+ mock_http = MagicMock()
26
+ aw = AgenticWalletResource(mock_http)
27
+ return aw, mock_http
28
+
29
+ def test_create_returns_wallet(self) -> None:
30
+ aw, mock_http = self._make_aw()
31
+ mock_http.post.return_value = {
32
+ "id": "aw-001",
33
+ "label": "Scraper Bot",
34
+ "balanceCents": 0,
35
+ "spendingLimitCents": 10000,
36
+ "status": "active",
37
+ "createdAt": "2024-06-01T00:00:00Z",
38
+ "dailyLimitCents": 500,
39
+ "allowedDomains": ["example.com"],
40
+ }
41
+
42
+ result = aw.create(
43
+ "Scraper Bot",
44
+ spending_limit_cents=10000,
45
+ daily_limit_cents=500,
46
+ allowed_domains=["example.com"],
47
+ )
48
+ assert isinstance(result, AgenticWallet)
49
+ assert result.id == "aw-001"
50
+ assert result.label == "Scraper Bot"
51
+ assert result.spending_limit_cents == 10000
52
+ assert result.daily_limit_cents == 500
53
+ assert result.allowed_domains == ["example.com"]
54
+ assert result.status == "active"
55
+
56
+ def test_create_minimal(self) -> None:
57
+ aw, mock_http = self._make_aw()
58
+ mock_http.post.return_value = {
59
+ "id": "aw-002",
60
+ "label": "Simple Bot",
61
+ "balanceCents": 0,
62
+ "spendingLimitCents": 5000,
63
+ "status": "active",
64
+ }
65
+
66
+ result = aw.create("Simple Bot", spending_limit_cents=5000)
67
+ assert result.label == "Simple Bot"
68
+ assert result.daily_limit_cents is None
69
+ assert result.allowed_domains is None
70
+ mock_http.post.assert_called_once_with(
71
+ "/api/agent-wallet",
72
+ json={"label": "Simple Bot", "spendingLimitCents": 5000},
73
+ )
74
+
75
+ def test_create_validates_spending_limit_zero(self) -> None:
76
+ aw, mock_http = self._make_aw()
77
+ with pytest.raises(ValueError, match="positive integer"):
78
+ aw.create("Bot", spending_limit_cents=0)
79
+
80
+ def test_create_validates_spending_limit_negative(self) -> None:
81
+ aw, mock_http = self._make_aw()
82
+ with pytest.raises(ValueError, match="positive integer"):
83
+ aw.create("Bot", spending_limit_cents=-100)
84
+
85
+ def test_create_validates_spending_limit_overflow(self) -> None:
86
+ aw, mock_http = self._make_aw()
87
+ with pytest.raises(ValueError, match="positive integer"):
88
+ aw.create("Bot", spending_limit_cents=2_147_483_648)
89
+
90
+ def test_create_validates_daily_limit(self) -> None:
91
+ aw, mock_http = self._make_aw()
92
+ with pytest.raises(ValueError, match="positive integer"):
93
+ aw.create("Bot", spending_limit_cents=10000, daily_limit_cents=0)
94
+
95
+ def test_create_401_raises(self) -> None:
96
+ aw, mock_http = self._make_aw()
97
+ mock_http.post.side_effect = AuthenticationError("Not authenticated")
98
+
99
+ with pytest.raises(AuthenticationError):
100
+ aw.create("Bot", spending_limit_cents=10000)
101
+
102
+
103
+ class TestAgenticWalletResourceList:
104
+ """Tests for AgenticWalletResource.list()."""
105
+
106
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
107
+ mock_http = MagicMock()
108
+ aw = AgenticWalletResource(mock_http)
109
+ return aw, mock_http
110
+
111
+ def test_list_returns_wallets(self) -> None:
112
+ aw, mock_http = self._make_aw()
113
+ mock_http.get.return_value = {
114
+ "wallets": [
115
+ {
116
+ "id": "aw-001",
117
+ "label": "Bot 1",
118
+ "balanceCents": 500,
119
+ "spendingLimitCents": 10000,
120
+ "status": "active",
121
+ },
122
+ {
123
+ "id": "aw-002",
124
+ "label": "Bot 2",
125
+ "balanceCents": 0,
126
+ "spendingLimitCents": 5000,
127
+ "status": "frozen",
128
+ },
129
+ ],
130
+ }
131
+
132
+ result = aw.list()
133
+ assert len(result) == 2
134
+ assert isinstance(result[0], AgenticWallet)
135
+ assert result[0].label == "Bot 1"
136
+ assert result[1].status == "frozen"
137
+
138
+ def test_list_empty(self) -> None:
139
+ aw, mock_http = self._make_aw()
140
+ mock_http.get.return_value = {"wallets": []}
141
+
142
+ result = aw.list()
143
+ assert result == []
144
+
145
+
146
+ class TestAgenticWalletResourceGet:
147
+ """Tests for AgenticWalletResource.get()."""
148
+
149
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
150
+ mock_http = MagicMock()
151
+ aw = AgenticWalletResource(mock_http)
152
+ return aw, mock_http
153
+
154
+ def test_get_returns_wallet(self) -> None:
155
+ aw, mock_http = self._make_aw()
156
+ mock_http.get.return_value = {
157
+ "id": "aw-001",
158
+ "label": "Scraper Bot",
159
+ "balanceCents": 2000,
160
+ "spendingLimitCents": 10000,
161
+ "status": "active",
162
+ "dailyLimitCents": 500,
163
+ "allowedDomains": ["example.com"],
164
+ }
165
+
166
+ result = aw.get("aw-001")
167
+ assert result.id == "aw-001"
168
+ assert result.balance_cents == 2000
169
+ mock_http.get.assert_called_once_with("/api/agent-wallet/aw-001")
170
+
171
+ def test_get_url_encodes_id(self) -> None:
172
+ aw, mock_http = self._make_aw()
173
+ mock_http.get.return_value = {
174
+ "id": "aw/special",
175
+ "label": "Test",
176
+ "balanceCents": 0,
177
+ "spendingLimitCents": 1000,
178
+ "status": "active",
179
+ }
180
+
181
+ aw.get("aw/special")
182
+ mock_http.get.assert_called_once_with("/api/agent-wallet/aw%2Fspecial")
183
+
184
+ def test_get_404_raises(self) -> None:
185
+ aw, mock_http = self._make_aw()
186
+ mock_http.get.side_effect = NotFoundError("Wallet not found")
187
+
188
+ with pytest.raises(NotFoundError, match="Wallet not found"):
189
+ aw.get("aw-nonexistent")
190
+
191
+
192
+ class TestAgenticWalletResourceFund:
193
+ """Tests for AgenticWalletResource.fund()."""
194
+
195
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
196
+ mock_http = MagicMock()
197
+ aw = AgenticWalletResource(mock_http)
198
+ return aw, mock_http
199
+
200
+ def test_fund_returns_transaction(self) -> None:
201
+ aw, mock_http = self._make_aw()
202
+ mock_http.post.return_value = {
203
+ "transaction": {
204
+ "id": "awtx-001",
205
+ "walletId": "aw-001",
206
+ "type": "fund",
207
+ "amountCents": 1000,
208
+ "description": "Fund from main wallet",
209
+ "sessionId": None,
210
+ "createdAt": "2024-06-01T00:00:00Z",
211
+ },
212
+ }
213
+
214
+ result = aw.fund("aw-001", 1000)
215
+ assert isinstance(result, AgenticWalletTransaction)
216
+ assert result.amount_cents == 1000
217
+ assert result.type == "fund"
218
+ assert result.wallet_id == "aw-001"
219
+
220
+ def test_fund_zero_raises(self) -> None:
221
+ aw, mock_http = self._make_aw()
222
+ with pytest.raises(ValueError, match="positive integer"):
223
+ aw.fund("aw-001", 0)
224
+
225
+ def test_fund_negative_raises(self) -> None:
226
+ aw, mock_http = self._make_aw()
227
+ with pytest.raises(ValueError, match="positive integer"):
228
+ aw.fund("aw-001", -500)
229
+
230
+ def test_fund_overflow_raises(self) -> None:
231
+ aw, mock_http = self._make_aw()
232
+ with pytest.raises(ValueError, match="positive integer"):
233
+ aw.fund("aw-001", 2_147_483_648)
234
+
235
+
236
+ class TestAgenticWalletResourceTransactions:
237
+ """Tests for AgenticWalletResource.transactions()."""
238
+
239
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
240
+ mock_http = MagicMock()
241
+ aw = AgenticWalletResource(mock_http)
242
+ return aw, mock_http
243
+
244
+ def test_transactions_returns_list(self) -> None:
245
+ aw, mock_http = self._make_aw()
246
+ mock_http.get.return_value = {
247
+ "transactions": [
248
+ {
249
+ "id": "awtx-001",
250
+ "walletId": "aw-001",
251
+ "type": "fund",
252
+ "amountCents": 1000,
253
+ "description": "Fund",
254
+ "createdAt": "2024-06-01",
255
+ },
256
+ {
257
+ "id": "awtx-002",
258
+ "walletId": "aw-001",
259
+ "type": "debit",
260
+ "amountCents": -50,
261
+ "description": "Usage",
262
+ "sessionId": "sess-abc",
263
+ "createdAt": "2024-06-02",
264
+ },
265
+ ],
266
+ }
267
+
268
+ result = aw.transactions("aw-001")
269
+ assert len(result) == 2
270
+ assert isinstance(result[0], AgenticWalletTransaction)
271
+ assert result[0].type == "fund"
272
+ assert result[1].session_id == "sess-abc"
273
+
274
+ def test_transactions_empty(self) -> None:
275
+ aw, mock_http = self._make_aw()
276
+ mock_http.get.return_value = {"transactions": []}
277
+
278
+ result = aw.transactions("aw-001")
279
+ assert result == []
280
+
281
+
282
+ class TestAgenticWalletResourceFreezeUnfreeze:
283
+ """Tests for AgenticWalletResource.freeze() and unfreeze()."""
284
+
285
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
286
+ mock_http = MagicMock()
287
+ aw = AgenticWalletResource(mock_http)
288
+ return aw, mock_http
289
+
290
+ def test_freeze_returns_frozen_wallet(self) -> None:
291
+ aw, mock_http = self._make_aw()
292
+ mock_http.post.return_value = {
293
+ "id": "aw-001",
294
+ "label": "Bot",
295
+ "balanceCents": 500,
296
+ "spendingLimitCents": 10000,
297
+ "status": "frozen",
298
+ }
299
+
300
+ result = aw.freeze("aw-001")
301
+ assert result.status == "frozen"
302
+ mock_http.post.assert_called_once_with("/api/agent-wallet/aw-001/freeze", json={})
303
+
304
+ def test_unfreeze_returns_active_wallet(self) -> None:
305
+ aw, mock_http = self._make_aw()
306
+ mock_http.post.return_value = {
307
+ "id": "aw-001",
308
+ "label": "Bot",
309
+ "balanceCents": 500,
310
+ "spendingLimitCents": 10000,
311
+ "status": "active",
312
+ }
313
+
314
+ result = aw.unfreeze("aw-001")
315
+ assert result.status == "active"
316
+ mock_http.post.assert_called_once_with("/api/agent-wallet/aw-001/unfreeze", json={})
317
+
318
+ def test_freeze_404_raises(self) -> None:
319
+ aw, mock_http = self._make_aw()
320
+ mock_http.post.side_effect = NotFoundError("Wallet not found")
321
+
322
+ with pytest.raises(NotFoundError):
323
+ aw.freeze("aw-nonexistent")
324
+
325
+ def test_unfreeze_403_raises(self) -> None:
326
+ aw, mock_http = self._make_aw()
327
+ mock_http.post.side_effect = AuthorizationError("Cannot unfreeze")
328
+
329
+ with pytest.raises(AuthorizationError):
330
+ aw.unfreeze("aw-001")
331
+
332
+
333
+ class TestAgenticWalletResourceDelete:
334
+ """Tests for AgenticWalletResource.delete()."""
335
+
336
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
337
+ mock_http = MagicMock()
338
+ aw = AgenticWalletResource(mock_http)
339
+ return aw, mock_http
340
+
341
+ def test_delete_returns_refunded_cents(self) -> None:
342
+ aw, mock_http = self._make_aw()
343
+ mock_http.delete.return_value = {"refundedCents": 450}
344
+
345
+ result = aw.delete("aw-001")
346
+ assert result == 450
347
+ mock_http.delete.assert_called_once_with("/api/agent-wallet/aw-001")
348
+
349
+ def test_delete_zero_refund(self) -> None:
350
+ aw, mock_http = self._make_aw()
351
+ mock_http.delete.return_value = {"refundedCents": 0}
352
+
353
+ result = aw.delete("aw-empty")
354
+ assert result == 0
355
+
356
+ def test_delete_404_raises(self) -> None:
357
+ aw, mock_http = self._make_aw()
358
+ mock_http.delete.side_effect = NotFoundError("Wallet not found")
359
+
360
+ with pytest.raises(NotFoundError):
361
+ aw.delete("aw-nonexistent")
362
+
363
+
364
+ class TestAgenticWalletResourceUpdatePolicy:
365
+ """Tests for AgenticWalletResource.update_wallet_policy()."""
366
+
367
+ def _make_aw(self) -> tuple[AgenticWalletResource, MagicMock]:
368
+ mock_http = MagicMock()
369
+ aw = AgenticWalletResource(mock_http)
370
+ return aw, mock_http
371
+
372
+ def test_update_policy_daily_limit(self) -> None:
373
+ aw, mock_http = self._make_aw()
374
+ mock_http.patch.return_value = {
375
+ "id": "aw-001",
376
+ "label": "Bot",
377
+ "balanceCents": 500,
378
+ "spendingLimitCents": 10000,
379
+ "status": "active",
380
+ "dailyLimitCents": 1000,
381
+ }
382
+
383
+ result = aw.update_wallet_policy("aw-001", daily_limit_cents=1000)
384
+ assert result.daily_limit_cents == 1000
385
+
386
+ def test_update_policy_allowed_domains(self) -> None:
387
+ aw, mock_http = self._make_aw()
388
+ mock_http.patch.return_value = {
389
+ "id": "aw-001",
390
+ "label": "Bot",
391
+ "balanceCents": 500,
392
+ "spendingLimitCents": 10000,
393
+ "status": "active",
394
+ "allowedDomains": ["api.example.com", "data.example.com"],
395
+ }
396
+
397
+ result = aw.update_wallet_policy(
398
+ "aw-001",
399
+ allowed_domains=["api.example.com", "data.example.com"],
400
+ )
401
+ assert result.allowed_domains == ["api.example.com", "data.example.com"]
402
+
403
+ def test_update_policy_validates_daily_limit(self) -> None:
404
+ aw, mock_http = self._make_aw()
405
+ with pytest.raises(ValueError, match="positive integer"):
406
+ aw.update_wallet_policy("aw-001", daily_limit_cents=0)
407
+
408
+ def test_update_policy_validates_daily_limit_overflow(self) -> None:
409
+ aw, mock_http = self._make_aw()
410
+ with pytest.raises(ValueError, match="positive integer"):
411
+ aw.update_wallet_policy("aw-001", daily_limit_cents=2_147_483_648)
412
+
413
+ def test_update_policy_url_encodes_id(self) -> None:
414
+ aw, mock_http = self._make_aw()
415
+ mock_http.patch.return_value = {
416
+ "id": "aw/special",
417
+ "label": "Bot",
418
+ "balanceCents": 0,
419
+ "spendingLimitCents": 1000,
420
+ "status": "active",
421
+ }
422
+
423
+ aw.update_wallet_policy("aw/special", allowed_domains=["test.com"])
424
+ mock_http.patch.assert_called_once_with(
425
+ "/api/agent-wallet/aw%2Fspecial/policy",
426
+ json={"allowedDomains": ["test.com"]},
427
+ )