Metadata-Version: 2.4
Name: lighthouse-private-markets-sdk
Version: 0.3.0
Summary: Python SDK for the Lighthouse REST API (CRM, Discovery, Reports, Documents).
Project-URL: Homepage, https://github.com/lighthouse-app/lighthouse-private-markets-sdk
Project-URL: Repository, https://github.com/lighthouse-app/lighthouse-private-markets-sdk.git
Author-email: Alberto Marzetta <hello@trylighthouse.vc>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.8
Requires-Dist: requests>=2.28
Description-Content-Type: text/markdown

# Lighthouse Python SDK

Official Python client for the [Lighthouse](https://trylighthouse.vc) REST API. Wraps the CRM, Discovery, Reports, and Documents endpoints behind a single typed `Lighthouse` class.

## Installation

```bash
pip install lighthouse-private-markets-sdk
```

## Quick Start

Generate an API key at **Settings → API Keys** in your Lighthouse workspace.

```python
from lighthouse import Lighthouse

client = Lighthouse("lgt_live_...")

# Who am I?
me = client.users.me()
print(me.data)

# Search your CRM
res = client.records.search(
    "company",
    filters={
        "operator": "AND",
        "conditions": [
            {"field": "domain", "operator": "contains_any", "value": ["acme.com"]}
        ],
    },
    limit=10,
)
print(res.data, res.meta)
```

Every method returns an `APIResponse`:

```python
class APIResponse:
    data:   Any                    # response payload
    error:  Any | None             # error message if the call failed
    meta:   dict | None            # pagination/meta info (when present)
    status: int                    # HTTP status code

res.raise_for_error()              # raises LighthouseError if error is set
```

## Authentication

The client sends `Authorization: Bearer <api_key>` on every request. Keep API keys secret — never ship them in client-side code.

## Resources

| Namespace             | Endpoints |
|-----------------------|-----------|
| `client.records`      | search / get / create / update / delete records (company, person, deal, custom objects) |
| `client.lists`        | list / get / create / update / delete, get_records, add_record, remove_record, share/revoke teams, update_sharing |
| `client.notes`        | list / get / create / delete, link_record, unlink_record |
| `client.tasks`        | list / get / create / update / delete |
| `client.attributes`   | list / get / create / update / delete, colors |
| `client.options`      | list / create / delete select-field options |
| `client.views`        | list / get / update / delete, share/revoke teams, update_sharing |
| `client.users`        | me, list, get |
| `client.teams`        | list, get |
| `client.dashboards`   | list / get / create / update / delete, list_widgets, create_widget, update_widget, delete_widget, widget_data, share/revoke teams |
| `client.discovery`    | get_attributes, search_companies, search_people, lookup_companies_by_domain, lookup_companies_by_linkedin, lookup_people_by_linkedin, get_saved_searches, get_search_results, get_locations, get_industries, get_tags, search_investors, search_organizations, search_schools |
| `client.documents`    | folders + files (v2): list_folders, create_folder, update_folder, delete_folder, link/unlink_folder, upload_url, finalize_file, get_file, update_file, delete_file, link/unlink_file, list_record_documents, `upload()` one-shot helper |

## Examples

### Records

```python
# Create
created = client.records.create("company", data={
    "name": "Acme",
    "domain": ["acme.com"],
})
record_id = created.data["id"]

# Update — relation fields are replaced entirely; pass the full desired array
client.records.update("company", record_id, data={"domain": ["acme.com", "acme.io"]})

# Get
client.records.get("company", record_id)

# Delete
client.records.delete("company", record_id)
```

### Filtering with attributes

```python
attrs = client.attributes.list(record_type="company").data
# pick a field permalink from attrs, then:
client.records.search(
    "company",
    filters={
        "operator": "AND",
        "conditions": [{"field": "headcount", "operator": "gte", "value": 50}],
    },
    sort=[{"field": "name", "direction": "asc"}],
    limit=25,
)
```

### Lists

```python
new_list = client.lists.create(name="Hot leads", record_type="company")
list_id = new_list.data["id"]

client.lists.add_record(list_id, record_id="…uuid…")
client.lists.get_records(list_id, limit=50)
```

### Notes

```python
client.notes.create(
    title="Intro call",
    content="<p>Met the founder, looking strong.</p>",
    records={"company": ["…uuid…"], "person": ["…uuid…"]},
)
```

### Tasks

```python
client.tasks.create(
    title="Send follow-up",
    due_date="2026-06-01",
    assigned_to=["…user_uuid…"],
    records={"company": ["…uuid…"]},
)
```

### Discovery

```python
# Always inspect attributes first to discover valid field keys
client.discovery.get_attributes(type="company")

# Search Lighthouse's global database
res = client.discovery.search_companies(
    filters={
        "operator": "AND",
        "conditions": [
            {"field": "company_hq_country", "operator": "contains_any", "value": ["US"]},
            {"field": "company_headcount", "operator": "between", "value": {"min": 10, "max": 200}},
        ],
    },
    limit=25,
)

# Enrich by domain / LinkedIn
client.discovery.lookup_companies_by_domain(["stripe.com", "openai.com"])
```

### Documents

```python
# One-shot helper handles upload-url + PUT + finalize
with open("pitch.pdf", "rb") as f:
    file = client.documents.upload(
        name="pitch.pdf",
        content=f.read(),
        content_type="application/pdf",
        sharing_status="WORKSPACE",
    )
file_id = file.data["id"]

# Attach to a record
client.documents.link_file_to_record(file_id, "company", "…uuid…")
```

## Error handling

```python
from lighthouse import Lighthouse, LighthouseError

client = Lighthouse("lgt_live_…")
try:
    res = client.records.search("company")
    res.raise_for_error()
    print(res.data)
except LighthouseError as e:
    print(f"API error ({e.status_code}):", e)
```

## Low-level escape hatch

For endpoints not yet wrapped by a namespace:

```python
res = client.request("GET", "/v1/some/new/endpoint", params={"foo": "bar"})
res = client.request("POST", "/v1/some/other", json={"hello": "world"})
```

## License

MIT — see [LICENSE](LICENSE).
