261 lines
8.1 KiB
Python
261 lines
8.1 KiB
Python
import os
|
|
import sys
|
|
|
|
import requests
|
|
|
|
|
|
class FolkAPI:
|
|
BASE_URL = "https://api.folk.app/v1"
|
|
|
|
def __init__(self, api_key: str):
|
|
self.headers = {"Authorization": f"Bearer {api_key}"}
|
|
|
|
def get_groups(self):
|
|
"""Fetch all groups from Folk."""
|
|
url = f"{self.BASE_URL}/groups"
|
|
response = requests.get(url, headers=self.headers)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
def create_company(
|
|
self,
|
|
name: str,
|
|
group_id: str = None,
|
|
website: str = None,
|
|
linkedin_url: str = None,
|
|
description: str = None,
|
|
emails=None,
|
|
phones=None,
|
|
addresses=None,
|
|
urls=None,
|
|
custom_field_values=None,
|
|
groups=None,
|
|
**kwargs,
|
|
):
|
|
"""Create a company (investor) in a specific group.
|
|
|
|
This method builds a payload matching Folk's Create Company API:
|
|
https://developer.folk.app/api-reference/companies/create-a-company
|
|
|
|
It keeps backward compatibility with the previous `group_id`,
|
|
`website` and `linkedin_url` arguments.
|
|
"""
|
|
url = f"{self.BASE_URL}/companies"
|
|
|
|
# Build the top-level payload expected by Folk
|
|
data = {"name": name}
|
|
if description:
|
|
data["description"] = description
|
|
|
|
# Groups: prefer explicit `groups`, else fall back to `group_id`
|
|
if groups:
|
|
# Accept either list of ids or list of dicts
|
|
formatted = []
|
|
for g in groups:
|
|
if isinstance(g, dict) and g.get("id"):
|
|
formatted.append({"id": g["id"]})
|
|
else:
|
|
formatted.append({"id": str(g)})
|
|
data["groups"] = formatted
|
|
elif group_id:
|
|
data["groups"] = [{"id": group_id}]
|
|
|
|
# Helper to normalize single or multiple inputs into lists
|
|
def _to_list(val):
|
|
if val is None:
|
|
return None
|
|
if isinstance(val, (list, tuple)):
|
|
return [v for v in val if v is not None]
|
|
return [val]
|
|
|
|
# URLs: include website and linkedin_url if provided and merge with urls
|
|
urls_list = _to_list(urls) or []
|
|
if website:
|
|
urls_list.append(website)
|
|
if linkedin_url:
|
|
urls_list.append(linkedin_url)
|
|
if urls_list:
|
|
data["urls"] = urls_list
|
|
|
|
# Emails/phones/addresses
|
|
emails_list = _to_list(emails)
|
|
if emails_list:
|
|
data["emails"] = emails_list
|
|
phones_list = _to_list(phones)
|
|
if phones_list:
|
|
data["phones"] = phones_list
|
|
addresses_list = _to_list(addresses)
|
|
if addresses_list:
|
|
data["addresses"] = addresses_list
|
|
|
|
# Custom field values follow the API's structure
|
|
if custom_field_values:
|
|
data["customFieldValues"] = custom_field_values
|
|
|
|
# Allow passing any additional top-level fields via kwargs (careful)
|
|
for k, v in kwargs.items():
|
|
# don't overwrite keys we explicitly set
|
|
if k not in data:
|
|
data[k] = v
|
|
|
|
response = requests.post(url, headers=self.headers, json=data)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
def create_person(
|
|
self,
|
|
first_name: str,
|
|
last_name: str,
|
|
email: str = None,
|
|
company_id: str = None,
|
|
group_id: str = None,
|
|
companies=None,
|
|
emails=None,
|
|
phones=None,
|
|
addresses=None,
|
|
urls=None,
|
|
custom_field_values=None,
|
|
groups=None,
|
|
**kwargs,
|
|
):
|
|
"""Create a person in the workspace.
|
|
|
|
Builds payload matching Folk's Create Person API: use camelCase
|
|
keys (firstName, lastName, groups, companies, emails, etc.).
|
|
Keeps backward compatibility with `company_id` and `group_id`.
|
|
"""
|
|
url = f"{self.BASE_URL}/people"
|
|
|
|
data = {"firstName": first_name, "lastName": last_name}
|
|
|
|
# Groups: explicit `groups` preferred, else fallback to `group_id`
|
|
if groups:
|
|
formatted = []
|
|
for g in groups:
|
|
if isinstance(g, dict) and g.get("id"):
|
|
formatted.append({"id": g["id"]})
|
|
else:
|
|
formatted.append({"id": str(g)})
|
|
data["groups"] = formatted
|
|
elif group_id:
|
|
data["groups"] = [{"id": group_id}]
|
|
|
|
# Companies: keep backward compatibility with company_id
|
|
if companies:
|
|
formatted = []
|
|
for c in companies:
|
|
if isinstance(c, dict):
|
|
formatted.append(c)
|
|
elif isinstance(c, str):
|
|
# treat as id
|
|
formatted.append({"id": c})
|
|
if formatted:
|
|
data["companies"] = formatted
|
|
elif company_id:
|
|
data["companies"] = [{"id": company_id}]
|
|
|
|
# Helper to normalize into lists
|
|
def _to_list(val):
|
|
if val is None:
|
|
return None
|
|
if isinstance(val, (list, tuple)):
|
|
return [v for v in val if v is not None]
|
|
return [val]
|
|
|
|
emails_list = _to_list(emails) or []
|
|
if email:
|
|
emails_list.insert(0, email)
|
|
if emails_list:
|
|
data["emails"] = emails_list
|
|
|
|
phones_list = _to_list(phones)
|
|
if phones_list:
|
|
data["phones"] = phones_list
|
|
addresses_list = _to_list(addresses)
|
|
if addresses_list:
|
|
data["addresses"] = addresses_list
|
|
urls_list = _to_list(urls)
|
|
if urls_list:
|
|
data["urls"] = urls_list
|
|
|
|
if custom_field_values:
|
|
data["customFieldValues"] = custom_field_values
|
|
|
|
# Allow passthrough of other top-level fields in kwargs
|
|
for k, v in kwargs.items():
|
|
if k not in data:
|
|
data[k] = v
|
|
|
|
response = requests.post(url, headers=self.headers, json=data)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
|
|
# Prefer getting the API key from the environment. If not set, fall back to the
|
|
# existing (hard-coded) key so behavior is unchanged for now.
|
|
DEFAULT_API_KEY = "FOLKfIGXuv74ML9EAajxyiUR39ePaNrZ"
|
|
api_key = os.environ.get("FOLK_API_KEY", DEFAULT_API_KEY)
|
|
|
|
folk = FolkAPI(api_key=api_key)
|
|
|
|
|
|
def example_flow():
|
|
# Step 1: Get groups
|
|
groups = folk.get_groups()
|
|
print(groups)
|
|
|
|
# Safely dig into the returned structure. The API returns groups under
|
|
# groups['data']['items'] (not groups['data'][0]). Handle missing/empty.
|
|
items = groups.get("data", {}).get("items", [])
|
|
if not items:
|
|
print("No groups returned by Folk API.")
|
|
sys.exit(1)
|
|
|
|
# Choose the first group as an example
|
|
group_id = items[0].get("id")
|
|
if not group_id:
|
|
print("No id found for the first group item.")
|
|
sys.exit(1)
|
|
|
|
# Step 2: Choose a group_id and create a company
|
|
company = folk.create_company(
|
|
name="2050 Investment Partners",
|
|
group_id=group_id,
|
|
website="https://2050.com",
|
|
linkedin_url="https://linkedin.com/company/2050-investments",
|
|
)
|
|
|
|
# Step 3: Add a person to the same group or company
|
|
person = folk.create_person(
|
|
first_name="John",
|
|
last_name="Doe",
|
|
email="john@2050.com",
|
|
company_id=company.get("data", {}).get("id"),
|
|
group_id=group_id,
|
|
)
|
|
|
|
print("Created company:", company)
|
|
print("Created person:", person)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
example_flow()
|
|
except requests.HTTPError as e:
|
|
# Try to include response body for easier debugging if available
|
|
resp = getattr(e, "response", None)
|
|
if resp is not None:
|
|
try:
|
|
body = resp.text
|
|
except Exception:
|
|
body = "<unreadable response body>"
|
|
print("HTTP error while talking to Folk API:", e)
|
|
print("Response status:", resp.status_code)
|
|
print("Response body:", body)
|
|
else:
|
|
print("HTTP error while talking to Folk API:", e)
|
|
sys.exit(1)
|
|
except Exception as e: # pragma: no cover - top-level safety
|
|
print("Unexpected error:", e)
|
|
sys.exit(1)
|