payelink-agent-pay 0.1.1
Payment processing SDK for Payelink Agent
License: MIT
Requires Python: >=3.13
Keywords: api, payelink, payment, sdk

# Payelink Agent Pay SDK

A Python SDK for wallet transfers through the Payelink Payment API. This SDK provides a simple and intuitive interface for transferring funds between wallets.

## Features

- Simple and intuitive API
- **Synchronous and asynchronous support**
- Type-safe with Pydantic models
- Automatic retry logic with exponential backoff
- HTTP client (httpx)
- Comprehensive error handling
- Payment-specific error types
- Wallet transfer functionality

## Installation

```bash
pip install payelink-agent-pay
```

Or using `uv`:

```bash
uv add payelink-agent-pay
```

## Quick Start

### Using API Key from .env file (Recommended)

Create a `.env` file in your project root:

```env
PAYELINK_KEY=your-api-key-here
```

Then initialize the client without providing the API key:

```python
from payelink_agent_pay import PaymentClient, WalletTransferRequest

# Initialize the client (API key loaded from PAYELINK_KEY in .env)
client = PaymentClient()

# Transfer funds between wallets
transfer_request = WalletTransferRequest(
    from_wallet_key="wal_yZnDhmBMxx4",
    to_wallet_key="wal_tPS-Nxnh-hc",
    value="12",
)

# Execute the transfer
transfer = client.wallet_transfer(transfer_request)
print(f"Transfer successful: {transfer.success}")
print(f"Transaction Hash: {transfer.data.transaction_hash}")
print(f"Chain: {transfer.data.chain}")
print(f"Network: {transfer.data.network}")
```

### Using API Key Explicitly

```python
from payelink_agent_pay import PaymentClient, WalletTransferRequest

# Initialize the client with explicit API key
client = PaymentClient(api_key="your-api-key")

# Transfer funds between wallets
transfer_request = WalletTransferRequest(
    from_wallet_key="wal_yZnDhmBMxx4",
    to_wallet_key="wal_tPS-Nxnh-hc",
    value="12",
)

# Execute the transfer
transfer = client.wallet_transfer(transfer_request)
print(f"Transfer successful: {transfer.success}")
print(f"Transaction Hash: {transfer.data.transaction_hash}")
print(f"Chain: {transfer.data.chain}")
print(f"Network: {transfer.data.network}")
```

## Usage Examples

### Wallet Transfer

#### Using .env file

```python
from payelink_agent_pay import PaymentClient, WalletTransferRequest

# API key loaded from PAYELINK_KEY in .env file
client = PaymentClient()
```

#### Using explicit API key

```python
from payelink_agent_pay import PaymentClient, WalletTransferRequest

client = PaymentClient(api_key="your-api-key")
```

# Transfer funds between wallets
transfer_request = WalletTransferRequest(
    from_wallet_key="wal_yZnDhmBMxx4",
    to_wallet_key="wal_tPS-Nxnh-hc",
    value="12",
)

try:
    transfer = client.wallet_transfer(transfer_request)
    if transfer.success:
        print(f"Transaction Hash: {transfer.data.transaction_hash}")
        print(f"From: {transfer.data.from_address}")
        print(f"To: {transfer.data.to_address}")
        print(f"Value: {transfer.data.value}")
        print(f"Chain: {transfer.data.chain}")
        print(f"Network: {transfer.data.network}")
        print(f"Message: {transfer.message}")
except Exception as e:
    print(f"Transfer failed: {e}")
```

### Using Context Manager

```python
# The client can be used as a context manager for automatic cleanup
# API key can be loaded from .env or provided explicitly
with PaymentClient() as client:  # or PaymentClient(api_key="your-api-key")
    transfer_request = WalletTransferRequest(
        from_wallet_key="wal_yZnDhmBMxx4",
        to_wallet_key="wal_tPS-Nxnh-hc",
        value="12",
    )
    transfer = client.wallet_transfer(transfer_request)
    # Client is automatically closed when exiting the context
```

## Async Usage

The SDK provides full async support through `AsyncPaymentClient` for concurrent operations and better performance in async applications.

### Quick Start with Async

```python
import asyncio
from payelink_agent_pay import AsyncPaymentClient, WalletTransferRequest

async def main():
    # Initialize the async client (API key loaded from PAYELINK_KEY in .env)
    async with AsyncPaymentClient() as client:
        transfer_request = WalletTransferRequest(
            from_wallet_key="wal_yZnDhmBMxx4",
            to_wallet_key="wal_tPS-Nxnh-hc",
            value="12",
        )
        
        # Execute the transfer asynchronously
        transfer = await client.wallet_transfer(transfer_request)
        print(f"Transfer successful: {transfer.success}")
        print(f"Transaction Hash: {transfer.data.transaction_hash}")

# Run the async function
asyncio.run(main())
```

### Async Client with Explicit API Key

```python
import asyncio
from payelink_agent_pay import AsyncPaymentClient, WalletTransferRequest

async def main():
    async with AsyncPaymentClient(api_key="your-api-key") as client:
        transfer_request = WalletTransferRequest(
            from_wallet_key="wal_yZnDhmBMxx4",
            to_wallet_key="wal_tPS-Nxnh-hc",
            value="12",
        )
        
        transfer = await client.wallet_transfer(transfer_request)
        print(f"Transaction Hash: {transfer.data.transaction_hash}")

asyncio.run(main())
```

### Concurrent Async Transfers

```python
import asyncio
from payelink_agent_pay import AsyncPaymentClient, WalletTransferRequest

async def transfer_funds(client: AsyncPaymentClient, from_wallet: str, to_wallet: str, amount: str):
    """Transfer funds between wallets."""
    request = WalletTransferRequest(
        from_wallet_key=from_wallet,
        to_wallet_key=to_wallet,
        value=amount,
    )
    return await client.wallet_transfer(request)

async def main():
    async with AsyncPaymentClient() as client:
        # Execute multiple transfers concurrently
        transfers = await asyncio.gather(
            transfer_funds(client, "wal_yZnDhmBMxx4", "wal_tPS-Nxnh-hc", "10"),
            transfer_funds(client, "wal_abc123", "wal_def456", "20"),
            transfer_funds(client, "wal_xyz789", "wal_uvw012", "15"),
        )
        
        for transfer in transfers:
            print(f"Transfer successful: {transfer.data.transaction_hash}")

asyncio.run(main())
```

### Async Error Handling

```python
import asyncio
from payelink_agent_pay import (
    AsyncPaymentClient,
    WalletTransferRequest,
    InsufficientFundsError,
    PaymentValidationError,
    PaymentAPIError,
)

async def main():
    async with AsyncPaymentClient() as client:
        transfer_request = WalletTransferRequest(
            from_wallet_key="wal_yZnDhmBMxx4",
            to_wallet_key="wal_tPS-Nxnh-hc",
            value="12",
        )
        
        try:
            transfer = await client.wallet_transfer(transfer_request)
            print(f"Transfer successful: {transfer.data.transaction_hash}")
        except InsufficientFundsError as e:
            print("Insufficient funds for this transfer")
        except PaymentValidationError as e:
            print("Transfer request validation failed")
        except PaymentAPIError as e:
            print(f"API error: {e.message} (Status: {e.status_code})")

asyncio.run(main())
```

## Configuration

### API Key Configuration

The SDK supports two ways to provide your API key:

1. **Environment Variable (Recommended)**: Create a `.env` file in your project root:
   ```env
   PAYELINK_KEY=your-api-key-here
   ```
   Then initialize the client without the `api_key` parameter:
   ```python
   client = PaymentClient()
   ```

2. **Explicit Parameter**: Pass the API key directly:
   ```python
   client = PaymentClient(api_key="your-api-key")
   ```

**Note**: If you provide both, the explicit `api_key` parameter takes precedence.

### Client Configuration

You can customize the client behavior for both sync and async clients:

**Synchronous Client:**
```python
client = PaymentClient(
    api_key="your-api-key",  # Optional if PAYELINK_KEY is in .env
    base_url="http://127.0.0.1:8000/v1",  # Optional
    timeout=30.0,  # Request timeout in seconds
    max_retries=3,  # Maximum retry attempts
    retry_delay=1.0,  # Delay between retries (seconds)
    verify_ssl=True,  # SSL certificate verification
)
```

**Asynchronous Client:**
```python
async_client = AsyncPaymentClient(
    api_key="your-api-key",  # Optional if PAYELINK_KEY is in .env
    base_url="http://127.0.0.1:8000/v1",  # Optional
    timeout=30.0,  # Request timeout in seconds
    max_retries=3,  # Maximum retry attempts
    retry_delay=1.0,  # Delay between retries (seconds)
    verify_ssl=True,  # SSL certificate verification
)
```

## Error Handling

The SDK provides specific error types for different scenarios:

```python
from payelink_agent_pay import (
    PaymentClient,
    InsufficientFundsError,
    PaymentValidationError,
    PaymentAPIError,
)

client = PaymentClient(api_key="your-api-key")

try:
    transfer = client.wallet_transfer(transfer_request)
except InsufficientFundsError as e:
    print("Insufficient funds for this transfer")
except PaymentValidationError as e:
    print("Transfer request validation failed")
except PaymentAPIError as e:
    print(f"API error: {e.message} (Status: {e.status_code})")
```

## Models

### WalletTransferRequest

```python
WalletTransferRequest(
    from_wallet_key: str,  # Required: Source wallet key
    to_wallet_key: str,  # Required: Destination wallet key
    value: str,  # Required: Transfer amount as string
)
```

### WalletTransferResponse

```python
WalletTransferResponse(
    success: bool,  # Whether the transfer was successful
    data: WalletTransferData,  # Transaction details
    message: str,  # Response message
)
```

### WalletTransferData

```python
WalletTransferData(
    transaction_hash: str,  # Transaction hash (mapped from transactionHash)
    chain: str,  # Blockchain chain name
    from_address: str,  # Source wallet address
    to_address: str,  # Destination wallet address
    value: str,  # Transfer amount
    network: str,  # Network type (testnet/mainnet)
)
```

## API Reference

### PaymentClient Methods (Synchronous)

- `wallet_transfer(request: WalletTransferRequest) -> WalletTransferResponse`
- `close() -> None`

### AsyncPaymentClient Methods (Asynchronous)

- `async wallet_transfer(request: WalletTransferRequest) -> WalletTransferResponse`
- `async close() -> None`

Both clients support context manager protocol:
- `PaymentClient`: `with PaymentClient() as client: ...`
- `AsyncPaymentClient`: `async with AsyncPaymentClient() as client: ...`

## Requirements

- Python >= 3.13
- httpx >= 0.24.0
- pydantic >= 2.0.0

## Development

### Setup

```bash
# Clone the repository
git clone https://github.com/payelink/payelink-agent-pay-sdk.git
cd payelink-agent-pay-sdk

# Install dependencies
uv sync

# Run tests (when available)
uv run pytest
```

### Building

```bash
uv build
```

### Publishing

For information on how to publish this package to PyPI, see [PUBLISHING.md](PUBLISHING.md).

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Support

For issues, questions, or contributions, please visit:
- GitHub Issues: https://github.com/payelink/payelink-agent-pay-sdk/issues
- Documentation: https://github.com/payelink/payelink-agent-pay-sdk#readme

## Changelog

### 0.2.0 (Upcoming)

- Added async support with `AsyncPaymentClient`
- Async context manager support
- Concurrent transfer operations support

### 0.1.0 (Initial Release)

- Initial release of Payelink Agent Pay SDK
- Wallet transfer functionality
- Comprehensive error handling
- Type-safe models with Pydantic