dotloop


Namedotloop JSON
Version 1.1.2 PyPI version JSON
download
home_pageNone
SummaryPython wrapper for Dotloop API - Real estate transaction management and document handling
upload_time2025-08-11 00:43:05
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords real-estate api dotloop transactions documents real-estate-api property-management real-estate-transactions
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Dotloop Python API Wrapper

A comprehensive Python wrapper for the Dotloop API v2, providing easy access to real estate transaction management and document handling functionality.

## Features

- **Complete API Coverage**: Implements all major Dotloop API endpoints
- **Type Safety**: Full type hints and Pydantic validation
- **Error Handling**: Comprehensive exception handling with detailed error messages
- **Easy to Use**: Intuitive client interface with method chaining
- **Well Documented**: Extensive docstrings and examples
- **Testing**: 100% test coverage with pytest

## Installation

```bash
pip install dotloop-api
```

## Quick Start

```python
from dotloop import DotloopClient, TransactionType, LoopStatus

# Initialize the client
client = DotloopClient(api_key="your_api_key")

# Or use environment variable DOTLOOP_API_KEY
client = DotloopClient()

# Get account information
account = client.account.get_account()
print(f"Account: {account['data']['firstName']} {account['data']['lastName']}")

# List profiles
profiles = client.profile.list_profiles()
for profile in profiles['data']:
    print(f"Profile: {profile['name']}")

# Create a new loop
loop = client.loop_it.create_loop(
    name="123 Main St Property",
    transaction_type=TransactionType.PURCHASE_OFFER,
    status=LoopStatus.PRE_OFFER,
    profile_id=123,
    street_number="123",
    street_name="Main St",
    city="San Francisco",
    state="CA",
    zip_code="94105"
)
```

## Authentication

The Dotloop API uses OAuth 2.0 Bearer tokens for authentication. You can obtain an access token through the OAuth flow and then use it with this wrapper.

### Setting up Authentication

1. **Environment Variable** (Recommended):
   ```bash
   export DOTLOOP_API_KEY="your_access_token"
   ```

2. **Direct Parameter**:
   ```python
   client = DotloopClient(api_key="your_access_token")
   ```

## Available Endpoints

### Account
- `client.account.get_account()` - Get current account details

### Profiles
- `client.profile.list_profiles()` - List all profiles
- `client.profile.get_profile(profile_id)` - Get profile by ID
- `client.profile.create_profile(...)` - Create a new profile
- `client.profile.update_profile(profile_id, ...)` - Update profile

### Loops
- `client.loop.list_loops(profile_id, ...)` - List loops for a profile
- `client.loop.get_loop(profile_id, loop_id)` - Get loop by ID
- `client.loop.create_loop(profile_id, ...)` - Create a new loop
- `client.loop.update_loop(profile_id, loop_id, ...)` - Update loop

### Loop-It (Simplified Loop Creation)
- `client.loop_it.create_loop(...)` - Create loop with property and participant data

### Contacts
- `client.contact.list_contacts()` - List all contacts
- `client.contact.get_contact(contact_id)` - Get contact by ID
- `client.contact.create_contact(...)` - Create a new contact
- `client.contact.update_contact(contact_id, ...)` - Update contact
- `client.contact.delete_contact(contact_id)` - Delete contact

## Examples

### Creating a Complete Real Estate Transaction

```python
from dotloop import DotloopClient, TransactionType, LoopStatus, ParticipantRole

client = DotloopClient()

# Create a comprehensive loop with property and participants
loop = client.loop_it.create_loop(
    name="John Doe - 456 Oak Avenue",
    transaction_type=TransactionType.PURCHASE_OFFER,
    status=LoopStatus.PRE_OFFER,
    profile_id=123,
    
    # Property information
    street_number="456",
    street_name="Oak Avenue",
    city="Los Angeles",
    state="CA",
    zip_code="90210",
    
    # Participants
    participants=[
        {
            "fullName": "John Doe",
            "email": "john.doe@example.com",
            "role": ParticipantRole.BUYER.value
        },
        {
            "fullName": "Jane Smith",
            "email": "jane.smith@realty.com",
            "role": ParticipantRole.BUYING_AGENT.value
        },
        {
            "fullName": "Bob Johnson",
            "email": "bob.johnson@realty.com",
            "role": ParticipantRole.LISTING_AGENT.value
        }
    ],
    
    # Optional MLS information
    mls_property_id="ML123456",
    template_id=1001
)

print(f"Created loop: {loop['data']['loopUrl']}")
```

### Managing Contacts

```python
# Create a new contact
contact = client.contact.create_contact(
    first_name="Alice",
    last_name="Johnson",
    email="alice.johnson@example.com",
    phone="+1 (555) 123-4567",
    company="Johnson Realty"
)

# Update the contact
updated_contact = client.contact.update_contact(
    contact_id=contact['data']['id'],
    phone="+1 (555) 987-6543",
    company="Johnson Premium Realty"
)

# List all contacts
contacts = client.contact.list_contacts()
for contact in contacts['data']:
    print(f"{contact['firstName']} {contact['lastName']} - {contact.get('email', 'No email')}")
```

### Working with Profiles

```python
# Create a new profile
profile = client.profile.create_profile(
    name="My Real Estate Business",
    company="ABC Realty",
    phone="+1 (555) 123-4567",
    address="123 Business Ave",
    city="New York",
    state="NY",
    zip_code="10001"
)

# List loops for this profile
loops = client.loop.list_loops(
    profile_id=profile['data']['id'],
    batch_size=50,
    sort="updated:desc",
    include_details=True
)
```

## Error Handling

The wrapper provides comprehensive error handling with specific exception types:

```python
from dotloop import DotloopClient
from dotloop.exceptions import (
    AuthenticationError,
    NotFoundError,
    ValidationError,
    RateLimitError
)

client = DotloopClient()

try:
    account = client.account.get_account()
except AuthenticationError:
    print("Invalid or expired API token")
except NotFoundError:
    print("Resource not found")
except ValidationError as e:
    print(f"Invalid parameters: {e}")
except RateLimitError:
    print("Rate limit exceeded, please wait")
```

## Enums and Constants

The wrapper provides enums for common values:

```python
from dotloop import (
    TransactionType,
    LoopStatus,
    ParticipantRole,
    SortDirection
)

# Transaction types
TransactionType.PURCHASE_OFFER
TransactionType.LISTING_FOR_SALE
TransactionType.PURCHASED
TransactionType.SOLD

# Loop statuses
LoopStatus.PRE_OFFER
LoopStatus.UNDER_CONTRACT
LoopStatus.SOLD
LoopStatus.ARCHIVED

# Participant roles
ParticipantRole.BUYER
ParticipantRole.SELLER
ParticipantRole.LISTING_AGENT
ParticipantRole.BUYING_AGENT
```

## Development

### Setting up Development Environment

```bash
# Clone the repository
git clone https://github.com/your-org/dotloop-python.git
cd dotloop-python

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements-dev.txt

# Run tests
pytest

# Run tests with coverage
pytest --cov=dotloop --cov-report=html
```

### Running Tests

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=dotloop

# Run specific test file
pytest tests/test_account.py

# Run with verbose output
pytest -v
```

## API Reference

For detailed API documentation, see the [official Dotloop API documentation](https://dotloop.github.io/public-api/).

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

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

## Support

- **Documentation**: [API Documentation](https://dotloop.github.io/public-api/)
- **Issues**: [GitHub Issues](https://github.com/your-org/dotloop-python/issues)
- **Email**: dev@theperry.group

## Changelog

### v1.0.0
- Initial release
- Complete implementation of core Dotloop API endpoints
- Account, Profile, Loop, Loop-It, and Contact management
- Comprehensive error handling and type safety
- 100% test coverage 

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dotloop",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "The Perry Group <dev@theperry.group>",
    "keywords": "real-estate, api, dotloop, transactions, documents, real-estate-api, property-management, real-estate-transactions",
    "author": null,
    "author_email": "The Perry Group <dev@theperry.group>",
    "download_url": "https://files.pythonhosted.org/packages/39/36/7474b3918b55fbee06b7a215b8689f8bfb43d0add569d753fab8718c5bbc/dotloop-1.1.2.tar.gz",
    "platform": null,
    "description": "# Dotloop Python API Wrapper\n\nA comprehensive Python wrapper for the Dotloop API v2, providing easy access to real estate transaction management and document handling functionality.\n\n## Features\n\n- **Complete API Coverage**: Implements all major Dotloop API endpoints\n- **Type Safety**: Full type hints and Pydantic validation\n- **Error Handling**: Comprehensive exception handling with detailed error messages\n- **Easy to Use**: Intuitive client interface with method chaining\n- **Well Documented**: Extensive docstrings and examples\n- **Testing**: 100% test coverage with pytest\n\n## Installation\n\n```bash\npip install dotloop-api\n```\n\n## Quick Start\n\n```python\nfrom dotloop import DotloopClient, TransactionType, LoopStatus\n\n# Initialize the client\nclient = DotloopClient(api_key=\"your_api_key\")\n\n# Or use environment variable DOTLOOP_API_KEY\nclient = DotloopClient()\n\n# Get account information\naccount = client.account.get_account()\nprint(f\"Account: {account['data']['firstName']} {account['data']['lastName']}\")\n\n# List profiles\nprofiles = client.profile.list_profiles()\nfor profile in profiles['data']:\n    print(f\"Profile: {profile['name']}\")\n\n# Create a new loop\nloop = client.loop_it.create_loop(\n    name=\"123 Main St Property\",\n    transaction_type=TransactionType.PURCHASE_OFFER,\n    status=LoopStatus.PRE_OFFER,\n    profile_id=123,\n    street_number=\"123\",\n    street_name=\"Main St\",\n    city=\"San Francisco\",\n    state=\"CA\",\n    zip_code=\"94105\"\n)\n```\n\n## Authentication\n\nThe Dotloop API uses OAuth 2.0 Bearer tokens for authentication. You can obtain an access token through the OAuth flow and then use it with this wrapper.\n\n### Setting up Authentication\n\n1. **Environment Variable** (Recommended):\n   ```bash\n   export DOTLOOP_API_KEY=\"your_access_token\"\n   ```\n\n2. **Direct Parameter**:\n   ```python\n   client = DotloopClient(api_key=\"your_access_token\")\n   ```\n\n## Available Endpoints\n\n### Account\n- `client.account.get_account()` - Get current account details\n\n### Profiles\n- `client.profile.list_profiles()` - List all profiles\n- `client.profile.get_profile(profile_id)` - Get profile by ID\n- `client.profile.create_profile(...)` - Create a new profile\n- `client.profile.update_profile(profile_id, ...)` - Update profile\n\n### Loops\n- `client.loop.list_loops(profile_id, ...)` - List loops for a profile\n- `client.loop.get_loop(profile_id, loop_id)` - Get loop by ID\n- `client.loop.create_loop(profile_id, ...)` - Create a new loop\n- `client.loop.update_loop(profile_id, loop_id, ...)` - Update loop\n\n### Loop-It (Simplified Loop Creation)\n- `client.loop_it.create_loop(...)` - Create loop with property and participant data\n\n### Contacts\n- `client.contact.list_contacts()` - List all contacts\n- `client.contact.get_contact(contact_id)` - Get contact by ID\n- `client.contact.create_contact(...)` - Create a new contact\n- `client.contact.update_contact(contact_id, ...)` - Update contact\n- `client.contact.delete_contact(contact_id)` - Delete contact\n\n## Examples\n\n### Creating a Complete Real Estate Transaction\n\n```python\nfrom dotloop import DotloopClient, TransactionType, LoopStatus, ParticipantRole\n\nclient = DotloopClient()\n\n# Create a comprehensive loop with property and participants\nloop = client.loop_it.create_loop(\n    name=\"John Doe - 456 Oak Avenue\",\n    transaction_type=TransactionType.PURCHASE_OFFER,\n    status=LoopStatus.PRE_OFFER,\n    profile_id=123,\n    \n    # Property information\n    street_number=\"456\",\n    street_name=\"Oak Avenue\",\n    city=\"Los Angeles\",\n    state=\"CA\",\n    zip_code=\"90210\",\n    \n    # Participants\n    participants=[\n        {\n            \"fullName\": \"John Doe\",\n            \"email\": \"john.doe@example.com\",\n            \"role\": ParticipantRole.BUYER.value\n        },\n        {\n            \"fullName\": \"Jane Smith\",\n            \"email\": \"jane.smith@realty.com\",\n            \"role\": ParticipantRole.BUYING_AGENT.value\n        },\n        {\n            \"fullName\": \"Bob Johnson\",\n            \"email\": \"bob.johnson@realty.com\",\n            \"role\": ParticipantRole.LISTING_AGENT.value\n        }\n    ],\n    \n    # Optional MLS information\n    mls_property_id=\"ML123456\",\n    template_id=1001\n)\n\nprint(f\"Created loop: {loop['data']['loopUrl']}\")\n```\n\n### Managing Contacts\n\n```python\n# Create a new contact\ncontact = client.contact.create_contact(\n    first_name=\"Alice\",\n    last_name=\"Johnson\",\n    email=\"alice.johnson@example.com\",\n    phone=\"+1 (555) 123-4567\",\n    company=\"Johnson Realty\"\n)\n\n# Update the contact\nupdated_contact = client.contact.update_contact(\n    contact_id=contact['data']['id'],\n    phone=\"+1 (555) 987-6543\",\n    company=\"Johnson Premium Realty\"\n)\n\n# List all contacts\ncontacts = client.contact.list_contacts()\nfor contact in contacts['data']:\n    print(f\"{contact['firstName']} {contact['lastName']} - {contact.get('email', 'No email')}\")\n```\n\n### Working with Profiles\n\n```python\n# Create a new profile\nprofile = client.profile.create_profile(\n    name=\"My Real Estate Business\",\n    company=\"ABC Realty\",\n    phone=\"+1 (555) 123-4567\",\n    address=\"123 Business Ave\",\n    city=\"New York\",\n    state=\"NY\",\n    zip_code=\"10001\"\n)\n\n# List loops for this profile\nloops = client.loop.list_loops(\n    profile_id=profile['data']['id'],\n    batch_size=50,\n    sort=\"updated:desc\",\n    include_details=True\n)\n```\n\n## Error Handling\n\nThe wrapper provides comprehensive error handling with specific exception types:\n\n```python\nfrom dotloop import DotloopClient\nfrom dotloop.exceptions import (\n    AuthenticationError,\n    NotFoundError,\n    ValidationError,\n    RateLimitError\n)\n\nclient = DotloopClient()\n\ntry:\n    account = client.account.get_account()\nexcept AuthenticationError:\n    print(\"Invalid or expired API token\")\nexcept NotFoundError:\n    print(\"Resource not found\")\nexcept ValidationError as e:\n    print(f\"Invalid parameters: {e}\")\nexcept RateLimitError:\n    print(\"Rate limit exceeded, please wait\")\n```\n\n## Enums and Constants\n\nThe wrapper provides enums for common values:\n\n```python\nfrom dotloop import (\n    TransactionType,\n    LoopStatus,\n    ParticipantRole,\n    SortDirection\n)\n\n# Transaction types\nTransactionType.PURCHASE_OFFER\nTransactionType.LISTING_FOR_SALE\nTransactionType.PURCHASED\nTransactionType.SOLD\n\n# Loop statuses\nLoopStatus.PRE_OFFER\nLoopStatus.UNDER_CONTRACT\nLoopStatus.SOLD\nLoopStatus.ARCHIVED\n\n# Participant roles\nParticipantRole.BUYER\nParticipantRole.SELLER\nParticipantRole.LISTING_AGENT\nParticipantRole.BUYING_AGENT\n```\n\n## Development\n\n### Setting up Development Environment\n\n```bash\n# Clone the repository\ngit clone https://github.com/your-org/dotloop-python.git\ncd dotloop-python\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate  # On Windows: venv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements-dev.txt\n\n# Run tests\npytest\n\n# Run tests with coverage\npytest --cov=dotloop --cov-report=html\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npytest\n\n# Run with coverage\npytest --cov=dotloop\n\n# Run specific test file\npytest tests/test_account.py\n\n# Run with verbose output\npytest -v\n```\n\n## API Reference\n\nFor detailed API documentation, see the [official Dotloop API documentation](https://dotloop.github.io/public-api/).\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Support\n\n- **Documentation**: [API Documentation](https://dotloop.github.io/public-api/)\n- **Issues**: [GitHub Issues](https://github.com/your-org/dotloop-python/issues)\n- **Email**: dev@theperry.group\n\n## Changelog\n\n### v1.0.0\n- Initial release\n- Complete implementation of core Dotloop API endpoints\n- Account, Profile, Loop, Loop-It, and Contact management\n- Comprehensive error handling and type safety\n- 100% test coverage \n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Python wrapper for Dotloop API - Real estate transaction management and document handling",
    "version": "1.1.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/theperrygroup/dotloop/issues",
        "Changelog": "https://github.com/theperrygroup/dotloop/blob/main/CHANGELOG.md",
        "Documentation": "https://dotloop.readthedocs.io",
        "Homepage": "https://github.com/theperrygroup/dotloop",
        "Repository": "https://github.com/theperrygroup/dotloop.git"
    },
    "split_keywords": [
        "real-estate",
        " api",
        " dotloop",
        " transactions",
        " documents",
        " real-estate-api",
        " property-management",
        " real-estate-transactions"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d7436bd5dfe3f7b86cb351167c4137406f919cc494e498d0e61b474a1d6eacec",
                "md5": "fab36609d8853b46e54f2783701908a3",
                "sha256": "8e3886ca37a6aa923384c143d57c25ccb701758275f543a23ecc9be7047ce442"
            },
            "downloads": -1,
            "filename": "dotloop-1.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fab36609d8853b46e54f2783701908a3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 36840,
            "upload_time": "2025-08-11T00:43:03",
            "upload_time_iso_8601": "2025-08-11T00:43:03.827570Z",
            "url": "https://files.pythonhosted.org/packages/d7/43/6bd5dfe3f7b86cb351167c4137406f919cc494e498d0e61b474a1d6eacec/dotloop-1.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "39367474b3918b55fbee06b7a215b8689f8bfb43d0add569d753fab8718c5bbc",
                "md5": "7ca5c55a0e67e2201f55dde10b463c7c",
                "sha256": "dd99fc904ca96f7404aaab244e50647b526e448d641073a0921f7aa5089ed8fb"
            },
            "downloads": -1,
            "filename": "dotloop-1.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "7ca5c55a0e67e2201f55dde10b463c7c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 37767,
            "upload_time": "2025-08-11T00:43:05",
            "upload_time_iso_8601": "2025-08-11T00:43:05.817007Z",
            "url": "https://files.pythonhosted.org/packages/39/36/7474b3918b55fbee06b7a215b8689f8bfb43d0add569d753fab8718c5bbc/dotloop-1.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-11 00:43:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "theperrygroup",
    "github_project": "dotloop",
    "github_not_found": true,
    "lcname": "dotloop"
}
        
Elapsed time: 1.53917s