crayfi 1.0.1
Official Python SDK for Cray Finance APIs
License: MIT
Requires Python: >=3.8

# Cray Finance Python SDK

[![PyPI version](https://badge.fury.io/py/crayfi.svg)](https://badge.fury.io/py/crayfi)

A first-class Python package for integrating Cray Finance APIs. This package abstracts authentication, HTTP calls, validation, retries, and error handling, providing a clean and expressive API for developers.

## Requirements

- Python 3.8+
- requests

## Installation

Install the package directly from PyPI:

```bash
pip install crayfi
```

## Configuration

You can configure the client using environment variables or by passing arguments directly to the client.

### Using Environment Variables

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

```env
CRAY_API_KEY=your_api_key_here
CRAY_ENV=sandbox
CRAY_TIMEOUT=30
CRAY_RETRIES=2
```

### Environment Switching

Set `CRAY_ENV` to `live` for production or `sandbox` for development/staging.

- `sandbox`: Uses `https://dev-gateman.v3.connectramp.com`
- `live`: Uses `https://pay.connectramp.com`

You can also explicitly set `CRAY_BASE_URL` if needed.

## Usage

Import the `Cray` client to access all modules.

```python
from cray import Cray

# Initialize the client (automatically loads from env if not provided)
cray = Cray(api_key="your_api_key") 
# OR just
# cray = Cray() 
```

### 1. Cards

Handle card transactions including initiation, charging, and querying.

```python
# Initiate a card transaction
# 'reference': A unique reference for this transaction (generated by you)
# 'amount': The amount to charge (in the smallest currency unit or standard unit as per API docs)
# 'currency': The currency code (e.g., USD, NGN)
# 'card_data': Sensitive card details (PAN, CVV, Expiry)
# 'customer_information': Details about the customer initiating the transaction
response = cray.cards.initiate({
    'reference': '4aeb118e-5009-450a-94fc-d74f6cd88646',
    'amount': '100',
    'currency': 'USD',
    'card_data': {
        'pan': '5399832641760090',
        'cvv': '146',
        'expiryMonth': '05',
        'expiryYear': '50',
    },
    'customer_information': {
        'email': 'test@testmail.com',
        'firstName': 'John',
        'lastName': 'Doe',
    }
})

# Process payment (Charge)
# 'transaction_id': The ID received from the initiate response or webhook
charge = cray.cards.charge({
    'transaction_id': 'SRK4NC92PFHLGZW78A3E'
})

# Query transaction status
# 'customer_reference_id': The unique reference you provided during initiation
status = cray.cards.query('customer_reference_id')
```

### 2. Mobile Money (MoMo)

Process mobile money payments.

```python
# Initiate MoMo payment
# 'payment_provider': The mobile money provider (e.g., MTN, Airtel)
# 'phone_no': The customer's phone number registered with the provider
momo = cray.momo.initiate({
    'customer_reference': 'e4d7c3b8-5f29-4b46-81a6-8d98c1e75812',
    'amount': '3950',
    'currency': 'XOF',
    'phone_no': '2290161248277',
    'payment_provider': 'MTN',
    'country': 'benin',
    'firstname': 'Cray',
    'lastname': 'Momo',
})

# Requery MoMo transaction
# Check the status of a transaction using your reference
status = cray.momo.requery('customer_reference_id')
```

### 3. Wallets

Fetch wallet balances.

```python
# Get all wallet balances
# Returns a list of balances for all currencies in your merchant wallet
balances = cray.wallets.balances()

# Get subaccounts
# Returns a list of subaccounts created under your merchant account
subaccounts = cray.wallets.subaccounts()
```

### 4. FX & Conversions

Handle exchange rates and currency conversions.

```python
# Get specific exchange rate
# Check the current rate between two currencies
rate = cray.fx.rates({
    'source_currency': 'USD',
    'destination_currency': 'NGN'
})

# Get rates by destination
# Get all available rates for a specific destination currency
rates = cray.fx.rates_by_destination({
    'destination_currency': 'NGN'
})

# Generate a quote
# Lock in a rate for a conversion (valid for a limited time)
quote = cray.fx.quote({
    'source_currency': 'NGN',
    'destination_currency': 'USD',
    'source_amount': 1500
})

# Execute conversion
# Finalize the conversion using the quote ID received from the quote step
conversion = cray.fx.convert({
    'quote_id': 'quote:98a5d6d3-7cbc-4c7d-b4f6-d3bbbbe340b6'
})

# Query conversions history
# Get a list of past conversions
history = cray.fx.conversions()
```

### 5. Payouts

Manage disbursements and transfers.

```python
# Get payment methods for a country
# Returns available payout methods (e.g., bank_transfer, mobile_money) for a specific country
methods = cray.payouts.payment_methods('NG')

# Get banks (optionally filter by country code)
# Returns a list of supported banks and their codes
banks = cray.payouts.banks('GH')

# Validate account name
# Verify that an account number belongs to a specific user before disbursing
account = cray.payouts.validate_account({
    'account_number': '0112345678',
    'bank_code': '058',
    'country_code': 'GH' # if applicable
})

# Disburse funds
# Send money to a beneficiary
transfer = cray.payouts.disburse({
    'customer_reference': 'ref-123',
    'account_number': '898789',
    'bank_code': '78978',
    'amount': '10',
    'currency': 'NGN',
    'narration': 'Payment for services',
    'sender_info': {'name': 'My Business'},
    'recipient_name': 'John Doe'
})

# Requery payout
# Check the status of a payout transaction
status = cray.payouts.requery('transaction_id')
```

### 6. Refunds

Initiate and track refunds.

```python
# Initiate a refund (full or partial)
# 'pan': Masked PAN or token of the card to be refunded
# 'subaccount_id': The subaccount that received the original payment (if applicable)
refund = cray.refunds.initiate({
    'pan': '4696660001638370',
    'subaccount_id': '9999999999',
    'amount': '1.2' # Optional, for partial refund
})

# Check refund status
status = cray.refunds.query('refund_reference_id')
```

## Error Handling

The package throws specific exceptions for different error scenarios. You should catch these exceptions to handle errors gracefully.

```python
from cray.exceptions import (
    CrayAuthenticationException,
    CrayValidationException,
    CrayTimeoutException,
    CrayApiException
)

try:
    response = cray.cards.initiate(payload)
except CrayAuthenticationException as e:
    # Handle invalid API key or unauthorized access
    print(f"Unauthorized: {e}")
except CrayValidationException as e:
    # Handle validation errors (400/422)
    # e.errors contains the validation details if available
    print(f"Validation Error: {e}")
except CrayTimeoutException as e:
    # Handle timeouts
    print("Request timed out")
except CrayApiException as e:
    # Handle other API errors (5xx, etc.)
    print(f"API Error: {e}")
```

## License

The MIT License (MIT).