Metadata-Version: 2.5
Name: alvaindes
Version: 0.1.0
Summary: Official Python SDK for the Alvaindes brokerage infrastructure API
Project-URL: Homepage, https://alvaindes.com
Project-URL: Repository, https://github.com/davidokani/alvaindes-python-sdk
Project-URL: Documentation, https://alvaindes.com/docs
Author: Alvaindes
License-Expression: MIT
License-File: LICENSE
Keywords: alvaindes,brokerage,brokerage-api,fintech,investment,trading
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx<1.0,>=0.27.0
Requires-Dist: typing-extensions>=4.0.0
Provides-Extra: dev
Requires-Dist: hatchling; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

# Alvaindes Python SDK

<p align="center">
  <img src="./assets/alvaindes.png" alt="Alvaindes Logo" width="140">
</p>

<h1 align="center">Alvaindes SDK</h1>

<p align="center">
  Official Python SDK for integrating Alvaindes brokerage infrastructure API.
</p>

<p align="center">
  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.
</p>

## Features

- Synchronous and asynchronous clients.
- Python 3.10 and newer.
- Typed request parameters and response objects.
- HTTP communication powered by [httpx](https://www.python-httpx.org/).
- Consistent API error handling.
- Context-manager support for client lifecycle management.
- Optional idempotency keys for supported financial operations.
- No automatic retries.

## Requirements

- Python 3.10+
- An Alvaindes API key.

## Installation

Install the SDK using pip:

```bash
pip install alvaindes
```

## Quick Start

### Synchronous Client

```python
from alvaindes import Alvaindes

with Alvaindes(api_key="YOUR_API_KEY") as client:
    user = client.users.get(
        application_id="YOUR_APPLICATION_ID",
        user_id="YOUR_USER_ID",
    )

    print(user)
```

### Asynchronous Client

```python
import asyncio

from alvaindes import AsyncAlvaindes


async def main():
    async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
        user = await client.users.get(
            application_id="YOUR_APPLICATION_ID",
            user_id="YOUR_USER_ID",
        )

        print(user)


asyncio.run(main())
```

Both clients expose the same resource capabilities. The asynchronous client uses `await` for API operations.

## Configuration

Both clients accept the following keyword arguments:

| Parameter  | Type    | Default                     | Description                      |
| ---------- | ------- | --------------------------- | -------------------------------- |
| `api_key`  | `str`   | Required                    | Your Alvaindes API key.          |
| `base_url` | `str`   | `https://api.alvaindes.com` | API origin.                      |
| `timeout`  | `float` | `30.0`                      | HTTP request timeout in seconds. |

Example:

```python
from alvaindes import Alvaindes

client = Alvaindes(
    api_key="YOUR_API_KEY",
    base_url="https://api.alvaindes.com",
    timeout=45.0,
)

try:
    user = client.users.get("YOUR_APPLICATION_ID", "YOUR_USER_ID")
    print(user)
finally:
    client.close()
```

The `base_url` must be an HTTP or HTTPS origin. Do not append `/v1`; the SDK includes the API version in its resource paths.

The API key is sent using the `x-api-key` HTTP header. The API determines the environment and permissions associated with the key.

Keep API keys private. Do not commit them to source control or expose them in client-side applications.

## Available Resources

The SDK exposes the following resources through both `Alvaindes` and `AsyncAlvaindes`.

| Resource             | Available Methods                             |
| -------------------- | --------------------------------------------- |
| `users`              | `create`, `get`                               |
| `accounts`           | `create`, `list`, `get`                       |
| `kyc`                | `submit`, `get`, `update`                     |
| `funding_sources`    | `create`, `list`, `refresh`, `disable`        |
| `portfolios`         | `get`                                         |
| `holdings`           | `list`                                        |
| `orders`             | `create`, `list`, `get`                       |
| `deposits`           | `create`                                      |
| `withdrawals`        | `create`                                      |
| `transactions`       | `list`                                        |
| `assets`             | `list`                                        |
| `market_data`        | `get_quote`                                   |
| `broker_agreements`  | `get_requirements`, `list_accepted`, `accept` |
| `broker_disclosures` | `get`, `create`                               |

## Resource Examples

All examples below use the synchronous client. The same operations are available through `AsyncAlvaindes` using `await`.

### 1. Users

Create and retrieve users associated with an application.

```python
user = client.users.create(
    application_id="YOUR_APPLICATION_ID",
    params={
        "firstName": "Jane",
        "lastName": "Doe",
        "email": "jane@example.com",
        "phoneNumber": "+1234567890",
        "country": "US",
    },
)

user = client.users.get(
    application_id="YOUR_APPLICATION_ID",
    user_id=user["id"],
)
```

### 2. Investment Accounts

Create, list, and retrieve investment accounts belonging to a user.

```python
account = client.accounts.create(
    user_id="YOUR_USER_ID",
    params={
        "currency": "USD",
        "brokerConnectionId": "YOUR_BROKER_CONNECTION_ID",
    },
)

accounts = client.accounts.list("YOUR_USER_ID")

account = client.accounts.get(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
)
```

### 3. KYC

Submit, retrieve, and update a user's Know Your Customer information.

```python
kyc = client.kyc.submit(
    user_id="YOUR_USER_ID",
    params={
        "countryOfResidence": "US",
        "dateOfBirth": "1990-01-15",
        "addressLine1": "123 Main Street",
        "addressCity": "New York",
        "documentType": "PASSPORT",
    },
)

kyc = client.kyc.get("YOUR_USER_ID")
```

Accepted document types:

- `PASSPORT`
- `NATIONAL_ID`
- `DRIVERS_LICENSE`
- `VOTERS_CARD`

Refer to the API documentation for the complete KYC submission and update fields.

### 4. Funding Sources

Create, list, refresh, and disable funding sources associated with an investment account.

```python
funding_source = client.funding_sources.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "type": "ACH",
        "ownerName": "Jane Doe",
        "bankAccountNumber": "YOUR_BANK_ACCOUNT_NUMBER",
        "bankAccountType": "checking",
        "routingNumber": "YOUR_ROUTING_NUMBER",
        "currency": "USD",
    },
)

funding_sources = client.funding_sources.list(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
)

funding_source = client.funding_sources.refresh(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
    funding_source_id="YOUR_FUNDING_SOURCE_ID",
)

funding_source = client.funding_sources.disable(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
    funding_source_id="YOUR_FUNDING_SOURCE_ID",
)
```

### 5. Portfolios and Holdings

Retrieve portfolio information and account holdings.

```python
portfolio = client.portfolios.get(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
)

holdings = client.holdings.list(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
)
```

### 6. Orders

Create, list, and retrieve investment orders.

**Market order:**

```python
order = client.orders.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "symbol": "AAPL",
        "side": "BUY",
        "quantity": 1,
        "type": "MARKET",
    },
)
```

**Limit order:**

```python
order = client.orders.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "symbol": "AAPL",
        "side": "BUY",
        "quantity": 1,
        "type": "LIMIT",
        "limitPrice": 200.00,
    },
)
```

**List orders:**

```python
orders = client.orders.list(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
)
```

**Retrieve an order:**

```python
order = client.orders.get(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
    "YOUR_ORDER_ID",
)
```

### 7. Deposits

Create a deposit into an investment account.

```python
deposit = client.deposits.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "amount": 100.00,
        "currency": "USD",
        "fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
    },
)
```

`fundingSourceId` is optional when the backend supports its configured funding-source selection behavior.

### 8. Withdrawals

Create a withdrawal from an investment account.

```python
withdrawal = client.withdrawals.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "amount": 50.00,
        "currency": "USD",
        "fundingSourceId": "YOUR_FUNDING_SOURCE_ID",
    },
)
```

### 9. Transactions

List transactions associated with an investment account.

```python
transactions = client.transactions.list(
    "YOUR_USER_ID",
    "YOUR_ACCOUNT_ID",
)
```

### 10. Assets

Search assets using the required connection ID and query.

```python
assets = client.assets.list(
    params={
        "connectionId": "YOUR_BROKER_CONNECTION_ID",
        "query": "AAPL",
    },
)
```

### 11. Market Data

Retrieve a quote for a symbol.

```python
quote = client.market_data.get_quote("AAPL")

print(quote["symbol"])
print(quote["price"])
print(quote["currency"])
print(quote["timestamp"])
```

The SDK URL-encodes symbols when constructing the request path.

### 12. Broker Agreements

Retrieve agreement requirements, list accepted agreements, and accept an agreement.

```python
requirements = client.broker_agreements.get_requirements(
    "YOUR_USER_ID",
    "YOUR_BROKER_CONNECTION_ID",
)

accepted = client.broker_agreements.list_accepted(
    "YOUR_USER_ID",
    "YOUR_BROKER_CONNECTION_ID",
)

agreement = client.broker_agreements.accept(
    "YOUR_USER_ID",
    "YOUR_BROKER_CONNECTION_ID",
    params={
        "agreement": "YOUR_AGREEMENT_TYPE",
    },
)
```

### 13. Broker Disclosures

Retrieve or create a user's broker disclosure.

```python
disclosure = client.broker_disclosures.create(
    "YOUR_USER_ID",
    "YOUR_BROKER_CONNECTION_ID",
    params={
        "employmentStatus": "EMPLOYED",
        "employmentSector": "TECHNOLOGY",
        "isControlPerson": False,
        "isAffiliatedExchangeOrFinra": False,
        "isPoliticallyExposed": False,
        "immediateFamilyExposed": False,
    },
)

disclosure = client.broker_disclosures.get(
    "YOUR_USER_ID",
    "YOUR_BROKER_CONNECTION_ID",
)
```

## Asynchronous Usage

Every resource listed above is also available on `AsyncAlvaindes`.

Example:

```python
import asyncio

from alvaindes import AsyncAlvaindes


async def main():
    async with AsyncAlvaindes(api_key="YOUR_API_KEY") as client:
        accounts = await client.accounts.list("YOUR_USER_ID")

        quote = await client.market_data.get_quote("AAPL")

        print(accounts)
        print(quote)


asyncio.run(main())
```

## Idempotency

The SDK supports optional idempotency keys on order, deposit, and withdrawal creation.

Example:

```python
order = client.orders.create(
    user_id="YOUR_USER_ID",
    account_id="YOUR_ACCOUNT_ID",
    params={
        "symbol": "AAPL",
        "side": "BUY",
        "quantity": 1,
        "type": "MARKET",
    },
    options={
        "idempotencyKey": "YOUR_UNIQUE_REQUEST_KEY",
    },
)
```

The same `options` pattern is supported by:

- `client.orders.create()`
- `client.deposits.create()`
- `client.withdrawals.create()`

The SDK sends the value using the `Idempotency-Key` HTTP header.

The SDK does not automatically retry requests. Applications should handle retries deliberately, particularly for financial operations, and use idempotency keys where supported.

## Error Handling

API and transport errors are exposed through `AlvaindesError`.

```python
from alvaindes import Alvaindes, AlvaindesError

try:
    with Alvaindes(api_key="YOUR_API_KEY") as client:
        user = client.users.get(
            "YOUR_APPLICATION_ID",
            "YOUR_USER_ID",
        )

except AlvaindesError as error:
    print("Message:", error.message)
    print("HTTP status:", error.status)
    print("Error code:", error.code)
    print("Response:", error.response)
```

The exception exposes the following attributes:

| Attribute  | Description                                             |
| ---------- | ------------------------------------------------------- |
| `message`  | Human-readable error message.                           |
| `status`   | HTTP status code, or `0` for a transport-level failure. |
| `code`     | API or transport error code when available.             |
| `response` | Parsed API response when available.                     |

Transport error codes include `TIMEOUT` and `NETWORK_ERROR`.

## Client Lifecycle

The synchronous client supports:

- `close()`
- `with` context management

The asynchronous client supports:

- `aclose()`
- `async with` context management

Using context managers is recommended because they close the underlying HTTP client automatically.

## Type Definitions

The SDK includes typed request parameters and response definitions.

Import types from `alvaindes.types`:

```python
from alvaindes.types import (
    CreateUserParams,
    InvestmentAccountResponse,
    MarketQuoteResponse,
    OrderResponse,
)
```

The types preserve the camelCase field names used by the Alvaindes API.

## Documentation and Links

- Website: https://alvaindes.com
- API documentation: https://alvaindes.com/docs
- GitHub repository: https://github.com/davidokani/alvaindes-python-sdk

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
