alvaindes 0.1.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 (70) hide show
  1. alvaindes-0.1.0/.gitignore +33 -0
  2. alvaindes-0.1.0/LICENSE +21 -0
  3. alvaindes-0.1.0/PKG-INFO +598 -0
  4. alvaindes-0.1.0/README.md +565 -0
  5. alvaindes-0.1.0/assets/alvaindes.png +0 -0
  6. alvaindes-0.1.0/pyproject.toml +73 -0
  7. alvaindes-0.1.0/src/alvaindes/__init__.py +8 -0
  8. alvaindes-0.1.0/src/alvaindes/client.py +152 -0
  9. alvaindes-0.1.0/src/alvaindes/config.py +44 -0
  10. alvaindes-0.1.0/src/alvaindes/errors.py +19 -0
  11. alvaindes-0.1.0/src/alvaindes/http/__init__.py +0 -0
  12. alvaindes-0.1.0/src/alvaindes/http/async_transport.py +95 -0
  13. alvaindes-0.1.0/src/alvaindes/http/sync_transport.py +95 -0
  14. alvaindes-0.1.0/src/alvaindes/http/transport.py +12 -0
  15. alvaindes-0.1.0/src/alvaindes/resources/__init__.py +69 -0
  16. alvaindes-0.1.0/src/alvaindes/resources/accounts.py +95 -0
  17. alvaindes-0.1.0/src/alvaindes/resources/assets.py +31 -0
  18. alvaindes-0.1.0/src/alvaindes/resources/async_base.py +32 -0
  19. alvaindes-0.1.0/src/alvaindes/resources/base.py +32 -0
  20. alvaindes-0.1.0/src/alvaindes/resources/broker_agreements.py +120 -0
  21. alvaindes-0.1.0/src/alvaindes/resources/broker_disclosures.py +87 -0
  22. alvaindes-0.1.0/src/alvaindes/resources/deposits.py +66 -0
  23. alvaindes-0.1.0/src/alvaindes/resources/funding_sources.py +155 -0
  24. alvaindes-0.1.0/src/alvaindes/resources/holdings.py +44 -0
  25. alvaindes-0.1.0/src/alvaindes/resources/kyc.py +98 -0
  26. alvaindes-0.1.0/src/alvaindes/resources/market_data.py +22 -0
  27. alvaindes-0.1.0/src/alvaindes/resources/orders.py +130 -0
  28. alvaindes-0.1.0/src/alvaindes/resources/portfolios.py +44 -0
  29. alvaindes-0.1.0/src/alvaindes/resources/transactions.py +44 -0
  30. alvaindes-0.1.0/src/alvaindes/resources/users.py +76 -0
  31. alvaindes-0.1.0/src/alvaindes/resources/withdrawals.py +66 -0
  32. alvaindes-0.1.0/src/alvaindes/types/__init__.py +89 -0
  33. alvaindes-0.1.0/src/alvaindes/types/accounts.py +15 -0
  34. alvaindes-0.1.0/src/alvaindes/types/assets.py +15 -0
  35. alvaindes-0.1.0/src/alvaindes/types/broker_agreements.py +24 -0
  36. alvaindes-0.1.0/src/alvaindes/types/broker_disclosures.py +26 -0
  37. alvaindes-0.1.0/src/alvaindes/types/deposits.py +22 -0
  38. alvaindes-0.1.0/src/alvaindes/types/funding_sources.py +34 -0
  39. alvaindes-0.1.0/src/alvaindes/types/holdings.py +9 -0
  40. alvaindes-0.1.0/src/alvaindes/types/kyc.py +66 -0
  41. alvaindes-0.1.0/src/alvaindes/types/market_data.py +8 -0
  42. alvaindes-0.1.0/src/alvaindes/types/orders.py +39 -0
  43. alvaindes-0.1.0/src/alvaindes/types/portfolios.py +11 -0
  44. alvaindes-0.1.0/src/alvaindes/types/transactions.py +13 -0
  45. alvaindes-0.1.0/src/alvaindes/types/users.py +24 -0
  46. alvaindes-0.1.0/src/alvaindes/types/withdrawals.py +22 -0
  47. alvaindes-0.1.0/tests/test_assets.py +61 -0
  48. alvaindes-0.1.0/tests/test_async_assets.py +67 -0
  49. alvaindes-0.1.0/tests/test_async_broker_agreements.py +146 -0
  50. alvaindes-0.1.0/tests/test_async_broker_disclosures.py +104 -0
  51. alvaindes-0.1.0/tests/test_async_deposits.py +105 -0
  52. alvaindes-0.1.0/tests/test_async_funding_sources.py +201 -0
  53. alvaindes-0.1.0/tests/test_async_holdings.py +47 -0
  54. alvaindes-0.1.0/tests/test_async_market_data.py +70 -0
  55. alvaindes-0.1.0/tests/test_async_orders.py +136 -0
  56. alvaindes-0.1.0/tests/test_async_portfolios.py +40 -0
  57. alvaindes-0.1.0/tests/test_async_transactions.py +65 -0
  58. alvaindes-0.1.0/tests/test_async_users.py +66 -0
  59. alvaindes-0.1.0/tests/test_async_withdrawals.py +107 -0
  60. alvaindes-0.1.0/tests/test_broker_agreements.py +136 -0
  61. alvaindes-0.1.0/tests/test_broker_disclosures.py +101 -0
  62. alvaindes-0.1.0/tests/test_deposits.py +97 -0
  63. alvaindes-0.1.0/tests/test_funding_sources.py +201 -0
  64. alvaindes-0.1.0/tests/test_holdings.py +47 -0
  65. alvaindes-0.1.0/tests/test_market_data.py +67 -0
  66. alvaindes-0.1.0/tests/test_orders.py +136 -0
  67. alvaindes-0.1.0/tests/test_portfolios.py +40 -0
  68. alvaindes-0.1.0/tests/test_transactions.py +59 -0
  69. alvaindes-0.1.0/tests/test_users.py +64 -0
  70. alvaindes-0.1.0/tests/test_withdrawals.py +99 -0
@@ -0,0 +1,33 @@
1
+ # Virtual environments
2
+ .venv/
3
+ venv/
4
+ env/
5
+
6
+ # Python cache
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+
11
+ # Test and coverage
12
+ .pytest_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # Build artifacts
17
+ build/
18
+ dist/
19
+ *.egg-info/
20
+
21
+ # Type checking
22
+ .mypy_cache/
23
+ .pyright/
24
+
25
+ # Environment variables and secrets
26
+ .env
27
+ .env.*
28
+ !.env.example
29
+
30
+ # IDE and OS files
31
+ .DS_Store
32
+ .idea/
33
+ .vscode/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alvaindes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,598 @@
1
+ Metadata-Version: 2.5
2
+ Name: alvaindes
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Alvaindes brokerage infrastructure API
5
+ Project-URL: Homepage, https://alvaindes.com
6
+ Project-URL: Repository, https://github.com/davidokani/alvaindes-python-sdk
7
+ Project-URL: Documentation, https://alvaindes.com/docs
8
+ Author: Alvaindes
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: alvaindes,brokerage,brokerage-api,fintech,investment,trading
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: httpx<1.0,>=0.27.0
25
+ Requires-Dist: typing-extensions>=4.0.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: hatchling; extra == 'dev'
28
+ Requires-Dist: mypy; extra == 'dev'
29
+ Requires-Dist: pytest; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio; extra == 'dev'
31
+ Requires-Dist: ruff; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Alvaindes Python SDK
35
+
36
+ <p align="center">
37
+ <img src="./assets/alvaindes.png" alt="Alvaindes Logo" width="140">
38
+ </p>
39
+
40
+ <h1 align="center">Alvaindes SDK</h1>
41
+
42
+ <p align="center">
43
+ Official Python SDK for integrating Alvaindes brokerage infrastructure API.
44
+ </p>
45
+
46
+ <p align="center">
47
+ The SDK provides synchronous and asynchronous Python clients for interacting with the public, versioned Alvaindes API. Use the SDK to work with users, investment accounts, KYC, assets, funding sources, portfolios, holdings, orders, deposits, withdrawals, transactions, broker agreements, broker disclosures, and market data.
48
+ </p>
49
+
50
+ ## Features
51
+
52
+ - Synchronous and asynchronous clients.
53
+ - Python 3.10 and newer.
54
+ - Typed request parameters and response objects.
55
+ - HTTP communication powered by [httpx](https://www.python-httpx.org/).
56
+ - Consistent API error handling.
57
+ - Context-manager support for client lifecycle management.
58
+ - Optional idempotency keys for supported financial operations.
59
+ - No automatic retries.
60
+
61
+ ## Requirements
62
+
63
+ - Python 3.10+
64
+ - An Alvaindes API key.
65
+
66
+ ## Installation
67
+
68
+ Install the SDK using pip:
69
+
70
+ ```bash
71
+ pip install alvaindes
72
+ ```
73
+
74
+ ## Quick Start
75
+
76
+ ### Synchronous Client
77
+
78
+ ```python
79
+ from alvaindes import Alvaindes
80
+
81
+ with Alvaindes(api_key="YOUR_API_KEY") as client:
82
+ user = client.users.get(
83
+ application_id="YOUR_APPLICATION_ID",
84
+ user_id="YOUR_USER_ID",
85
+ )
86
+
87
+ print(user)
88
+ ```
89
+
90
+ ### Asynchronous Client
91
+
92
+ ```python
93
+ import asyncio
94
+
95
+ from alvaindes import AsyncAlvaindes
96
+
97
+
98
+ async def main():
99
+ async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
100
+ user = await client.users.get(
101
+ application_id="YOUR_APPLICATION_ID",
102
+ user_id="YOUR_USER_ID",
103
+ )
104
+
105
+ print(user)
106
+
107
+
108
+ asyncio.run(main())
109
+ ```
110
+
111
+ Both clients expose the same resource capabilities. The asynchronous client uses `await` for API operations.
112
+
113
+ ## Configuration
114
+
115
+ Both clients accept the following keyword arguments:
116
+
117
+ | Parameter | Type | Default | Description |
118
+ | ---------- | ------- | --------------------------- | -------------------------------- |
119
+ | `api_key` | `str` | Required | Your Alvaindes API key. |
120
+ | `base_url` | `str` | `https://api.alvaindes.com` | API origin. |
121
+ | `timeout` | `float` | `30.0` | HTTP request timeout in seconds. |
122
+
123
+ Example:
124
+
125
+ ```python
126
+ from alvaindes import Alvaindes
127
+
128
+ client = Alvaindes(
129
+ api_key="YOUR_API_KEY",
130
+ base_url="https://api.alvaindes.com",
131
+ timeout=45.0,
132
+ )
133
+
134
+ try:
135
+ user = client.users.get("YOUR_APPLICATION_ID", "YOUR_USER_ID")
136
+ print(user)
137
+ finally:
138
+ client.close()
139
+ ```
140
+
141
+ The `base_url` must be an HTTP or HTTPS origin. Do not append `/v1`; the SDK includes the API version in its resource paths.
142
+
143
+ The API key is sent using the `x-api-key` HTTP header. The API determines the environment and permissions associated with the key.
144
+
145
+ Keep API keys private. Do not commit them to source control or expose them in client-side applications.
146
+
147
+ ## Available Resources
148
+
149
+ The SDK exposes the following resources through both `Alvaindes` and `AsyncAlvaindes`.
150
+
151
+ | Resource | Available Methods |
152
+ | -------------------- | --------------------------------------------- |
153
+ | `users` | `create`, `get` |
154
+ | `accounts` | `create`, `list`, `get` |
155
+ | `kyc` | `submit`, `get`, `update` |
156
+ | `funding_sources` | `create`, `list`, `refresh`, `disable` |
157
+ | `portfolios` | `get` |
158
+ | `holdings` | `list` |
159
+ | `orders` | `create`, `list`, `get` |
160
+ | `deposits` | `create` |
161
+ | `withdrawals` | `create` |
162
+ | `transactions` | `list` |
163
+ | `assets` | `list` |
164
+ | `market_data` | `get_quote` |
165
+ | `broker_agreements` | `get_requirements`, `list_accepted`, `accept` |
166
+ | `broker_disclosures` | `get`, `create` |
167
+
168
+ ## Resource Examples
169
+
170
+ All examples below use the synchronous client. The same operations are available through `AsyncAlvaindes` using `await`.
171
+
172
+ ### 1. Users
173
+
174
+ Create and retrieve users associated with an application.
175
+
176
+ ```python
177
+ user = client.users.create(
178
+ application_id="YOUR_APPLICATION_ID",
179
+ params={
180
+ "firstName": "Jane",
181
+ "lastName": "Doe",
182
+ "email": "jane@example.com",
183
+ "phoneNumber": "+1234567890",
184
+ "country": "US",
185
+ },
186
+ )
187
+
188
+ user = client.users.get(
189
+ application_id="YOUR_APPLICATION_ID",
190
+ user_id=user["id"],
191
+ )
192
+ ```
193
+
194
+ ### 2. Investment Accounts
195
+
196
+ Create, list, and retrieve investment accounts belonging to a user.
197
+
198
+ ```python
199
+ account = client.accounts.create(
200
+ user_id="YOUR_USER_ID",
201
+ params={
202
+ "currency": "USD",
203
+ "brokerConnectionId": "YOUR_BROKER_CONNECTION_ID",
204
+ },
205
+ )
206
+
207
+ accounts = client.accounts.list("YOUR_USER_ID")
208
+
209
+ account = client.accounts.get(
210
+ user_id="YOUR_USER_ID",
211
+ account_id="YOUR_ACCOUNT_ID",
212
+ )
213
+ ```
214
+
215
+ ### 3. KYC
216
+
217
+ Submit, retrieve, and update a user's Know Your Customer information.
218
+
219
+ ```python
220
+ kyc = client.kyc.submit(
221
+ user_id="YOUR_USER_ID",
222
+ params={
223
+ "countryOfResidence": "US",
224
+ "dateOfBirth": "1990-01-15",
225
+ "addressLine1": "123 Main Street",
226
+ "addressCity": "New York",
227
+ "documentType": "PASSPORT",
228
+ },
229
+ )
230
+
231
+ kyc = client.kyc.get("YOUR_USER_ID")
232
+ ```
233
+
234
+ Accepted document types:
235
+
236
+ - `PASSPORT`
237
+ - `NATIONAL_ID`
238
+ - `DRIVERS_LICENSE`
239
+ - `VOTERS_CARD`
240
+
241
+ Refer to the API documentation for the complete KYC submission and update fields.
242
+
243
+ ### 4. Funding Sources
244
+
245
+ Create, list, refresh, and disable funding sources associated with an investment account.
246
+
247
+ ```python
248
+ funding_source = client.funding_sources.create(
249
+ user_id="YOUR_USER_ID",
250
+ account_id="YOUR_ACCOUNT_ID",
251
+ params={
252
+ "type": "ACH",
253
+ "ownerName": "Jane Doe",
254
+ "bankAccountNumber": "YOUR_BANK_ACCOUNT_NUMBER",
255
+ "bankAccountType": "checking",
256
+ "routingNumber": "YOUR_ROUTING_NUMBER",
257
+ "currency": "USD",
258
+ },
259
+ )
260
+
261
+ funding_sources = client.funding_sources.list(
262
+ "YOUR_USER_ID",
263
+ "YOUR_ACCOUNT_ID",
264
+ )
265
+
266
+ funding_source = client.funding_sources.refresh(
267
+ "YOUR_USER_ID",
268
+ "YOUR_ACCOUNT_ID",
269
+ funding_source_id="YOUR_FUNDING_SOURCE_ID",
270
+ )
271
+
272
+ funding_source = client.funding_sources.disable(
273
+ "YOUR_USER_ID",
274
+ "YOUR_ACCOUNT_ID",
275
+ funding_source_id="YOUR_FUNDING_SOURCE_ID",
276
+ )
277
+ ```
278
+
279
+ ### 5. Portfolios and Holdings
280
+
281
+ Retrieve portfolio information and account holdings.
282
+
283
+ ```python
284
+ portfolio = client.portfolios.get(
285
+ "YOUR_USER_ID",
286
+ "YOUR_ACCOUNT_ID",
287
+ )
288
+
289
+ holdings = client.holdings.list(
290
+ "YOUR_USER_ID",
291
+ "YOUR_ACCOUNT_ID",
292
+ )
293
+ ```
294
+
295
+ ### 6. Orders
296
+
297
+ Create, list, and retrieve investment orders.
298
+
299
+ **Market order:**
300
+
301
+ ```python
302
+ order = client.orders.create(
303
+ user_id="YOUR_USER_ID",
304
+ account_id="YOUR_ACCOUNT_ID",
305
+ params={
306
+ "symbol": "AAPL",
307
+ "side": "BUY",
308
+ "quantity": 1,
309
+ "type": "MARKET",
310
+ },
311
+ )
312
+ ```
313
+
314
+ **Limit order:**
315
+
316
+ ```python
317
+ order = client.orders.create(
318
+ user_id="YOUR_USER_ID",
319
+ account_id="YOUR_ACCOUNT_ID",
320
+ params={
321
+ "symbol": "AAPL",
322
+ "side": "BUY",
323
+ "quantity": 1,
324
+ "type": "LIMIT",
325
+ "limitPrice": 200.00,
326
+ },
327
+ )
328
+ ```
329
+
330
+ **List orders:**
331
+
332
+ ```python
333
+ orders = client.orders.list(
334
+ "YOUR_USER_ID",
335
+ "YOUR_ACCOUNT_ID",
336
+ )
337
+ ```
338
+
339
+ **Retrieve an order:**
340
+
341
+ ```python
342
+ order = client.orders.get(
343
+ "YOUR_USER_ID",
344
+ "YOUR_ACCOUNT_ID",
345
+ "YOUR_ORDER_ID",
346
+ )
347
+ ```
348
+
349
+ ### 7. Deposits
350
+
351
+ Create a deposit into an investment account.
352
+
353
+ ```python
354
+ deposit = client.deposits.create(
355
+ user_id="YOUR_USER_ID",
356
+ account_id="YOUR_ACCOUNT_ID",
357
+ params={
358
+ "amount": 100.00,
359
+ "currency": "USD",
360
+ "fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
361
+ },
362
+ )
363
+ ```
364
+
365
+ `fundingSourceId` is optional when the backend supports its configured funding-source selection behavior.
366
+
367
+ ### 8. Withdrawals
368
+
369
+ Create a withdrawal from an investment account.
370
+
371
+ ```python
372
+ withdrawal = client.withdrawals.create(
373
+ user_id="YOUR_USER_ID",
374
+ account_id="YOUR_ACCOUNT_ID",
375
+ params={
376
+ "amount": 50.00,
377
+ "currency": "USD",
378
+ "fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
379
+ },
380
+ )
381
+ ```
382
+
383
+ ### 9. Transactions
384
+
385
+ List transactions associated with an investment account.
386
+
387
+ ```python
388
+ transactions = client.transactions.list(
389
+ "YOUR_USER_ID",
390
+ "YOUR_ACCOUNT_ID",
391
+ )
392
+ ```
393
+
394
+ ### 10. Assets
395
+
396
+ Search assets using the required connection ID and query.
397
+
398
+ ```python
399
+ assets = client.assets.list(
400
+ params={
401
+ "connectionId": "YOUR_BROKER_CONNECTION_ID",
402
+ "query": "AAPL",
403
+ },
404
+ )
405
+ ```
406
+
407
+ ### 11. Market Data
408
+
409
+ Retrieve a quote for a symbol.
410
+
411
+ ```python
412
+ quote = client.market_data.get_quote("AAPL")
413
+
414
+ print(quote["symbol"])
415
+ print(quote["price"])
416
+ print(quote["currency"])
417
+ print(quote["timestamp"])
418
+ ```
419
+
420
+ The SDK URL-encodes symbols when constructing the request path.
421
+
422
+ ### 12. Broker Agreements
423
+
424
+ Retrieve agreement requirements, list accepted agreements, and accept an agreement.
425
+
426
+ ```python
427
+ requirements = client.broker_agreements.get_requirements(
428
+ "YOUR_USER_ID",
429
+ "YOUR_BROKER_CONNECTION_ID",
430
+ )
431
+
432
+ accepted = client.broker_agreements.list_accepted(
433
+ "YOUR_USER_ID",
434
+ "YOUR_BROKER_CONNECTION_ID",
435
+ )
436
+
437
+ agreement = client.broker_agreements.accept(
438
+ "YOUR_USER_ID",
439
+ "YOUR_BROKER_CONNECTION_ID",
440
+ params={
441
+ "agreement": "YOUR_AGREEMENT_TYPE",
442
+ },
443
+ )
444
+ ```
445
+
446
+ ### 13. Broker Disclosures
447
+
448
+ Retrieve or create a user's broker disclosure.
449
+
450
+ ```python
451
+ disclosure = client.broker_disclosures.create(
452
+ "YOUR_USER_ID",
453
+ "YOUR_BROKER_CONNECTION_ID",
454
+ params={
455
+ "employmentStatus": "EMPLOYED",
456
+ "employmentSector": "TECHNOLOGY",
457
+ "isControlPerson": False,
458
+ "isAffiliatedExchangeOrFinra": False,
459
+ "isPoliticallyExposed": False,
460
+ "immediateFamilyExposed": False,
461
+ },
462
+ )
463
+
464
+ disclosure = client.broker_disclosures.get(
465
+ "YOUR_USER_ID",
466
+ "YOUR_BROKER_CONNECTION_ID",
467
+ )
468
+ ```
469
+
470
+ ## Asynchronous Usage
471
+
472
+ Every resource listed above is also available on `AsyncAlvaindes`.
473
+
474
+ Example:
475
+
476
+ ```python
477
+ import asyncio
478
+
479
+ from alvaindes import AsyncAlvaindes
480
+
481
+
482
+ async def main():
483
+ async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
484
+ accounts = await client.accounts.list("YOUR_USER_ID")
485
+
486
+ quote = await client.market_data.get_quote("AAPL")
487
+
488
+ print(accounts)
489
+ print(quote)
490
+
491
+
492
+ asyncio.run(main())
493
+ ```
494
+
495
+ ## Idempotency
496
+
497
+ The SDK supports optional idempotency keys on order, deposit, and withdrawal creation.
498
+
499
+ Example:
500
+
501
+ ```python
502
+ order = client.orders.create(
503
+ user_id="YOUR_USER_ID",
504
+ account_id="YOUR_ACCOUNT_ID",
505
+ params={
506
+ "symbol": "AAPL",
507
+ "side": "BUY",
508
+ "quantity": 1,
509
+ "type": "MARKET",
510
+ },
511
+ options={
512
+ "idempotencyKey": "YOUR_UNIQUE_REQUEST_KEY",
513
+ },
514
+ )
515
+ ```
516
+
517
+ The same `options` pattern is supported by:
518
+
519
+ - `client.orders.create()`
520
+ - `client.deposits.create()`
521
+ - `client.withdrawals.create()`
522
+
523
+ The SDK sends the value using the `Idempotency-Key` HTTP header.
524
+
525
+ The SDK does not automatically retry requests. Applications should handle retries deliberately, particularly for financial operations, and use idempotency keys where supported.
526
+
527
+ ## Error Handling
528
+
529
+ API and transport errors are exposed through `AlvaindesError`.
530
+
531
+ ```python
532
+ from alvaindes import Alvaindes, AlvaindesError
533
+
534
+ try:
535
+ with Alvaindes(api_key="YOUR_API_KEY") as client:
536
+ user = client.users.get(
537
+ "YOUR_APPLICATION_ID",
538
+ "YOUR_USER_ID",
539
+ )
540
+
541
+ except AlvaindesError as error:
542
+ print("Message:", error.message)
543
+ print("HTTP status:", error.status)
544
+ print("Error code:", error.code)
545
+ print("Response:", error.response)
546
+ ```
547
+
548
+ The exception exposes the following attributes:
549
+
550
+ | Attribute | Description |
551
+ | ---------- | ------------------------------------------------------- |
552
+ | `message` | Human-readable error message. |
553
+ | `status` | HTTP status code, or `0` for a transport-level failure. |
554
+ | `code` | API or transport error code when available. |
555
+ | `response` | Parsed API response when available. |
556
+
557
+ Transport error codes include `TIMEOUT` and `NETWORK_ERROR`.
558
+
559
+ ## Client Lifecycle
560
+
561
+ The synchronous client supports:
562
+
563
+ - `close()`
564
+ - `with` context management
565
+
566
+ The asynchronous client supports:
567
+
568
+ - `aclose()`
569
+ - `async with` context management
570
+
571
+ Using context managers is recommended because they close the underlying HTTP client automatically.
572
+
573
+ ## Type Definitions
574
+
575
+ The SDK includes typed request parameters and response definitions.
576
+
577
+ Import types from `alvaindes.types`:
578
+
579
+ ```python
580
+ from alvaindes.types import (
581
+ CreateUserParams,
582
+ InvestmentAccountResponse,
583
+ MarketQuoteResponse,
584
+ OrderResponse,
585
+ )
586
+ ```
587
+
588
+ The types preserve the camelCase field names used by the Alvaindes API.
589
+
590
+ ## Documentation and Links
591
+
592
+ - Website: https://alvaindes.com
593
+ - API documentation: https://alvaindes.com/docs
594
+ - GitHub repository: https://github.com/davidokani/alvaindes-python-sdk
595
+
596
+ ## License
597
+
598
+ This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.