Metadata-Version: 2.4
Name: facilio-connections-sdk
Version: 0.1.1
Summary: Python client for Facilio Connections cloud-server /api/v1 Tier 1 API
Author: Facilio
License-Expression: LicenseRef-Facilio-Proprietary
Keywords: facilio,connections,api,http,client,httpx
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<0.29,>=0.27
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# Facilio Connections SDK (Python)

Integrator client for Connections **`/api/v1`** using **httpx**. Concepts: [../README.md](../README.md). HTTP paths, JSON shapes, headers: [../docs/api-reference.md](../docs/api-reference.md).

**Requirements:** Python **3.10+**. **Import package:** `facilio_connections_sdk`.

---

## Installation

**pip** :

```bash
pip install facilio-connections-sdk
```

---

## Walkthrough

Linear script-style example. With the default internal **httpx** client, call **`client.close()`** when finished (or pass your own **`http_client`**).

```python
from facilio_connections_sdk import ConnectionsClient

# initialize connections client

client = ConnectionsClient("https://your-host", "your-service-token")

'''
Using Cookies instead of service token

 cfg = ConnectionsClientConfig(
    base_url="https://connections.facilio.com",
    service_token=None,
    csrf_token="",
    extra_headers={
        "Cookie": "fc.idToken.connections=xxxxxxxx; JSESSIONID=xxxxxx",
    },
    timeout_seconds=120.0,
)

client = ConnectionsClient.from_config(cfg) '''


# list connections
print(client.list_connections())


# get connection name
print(client.get_connection("servicenow-connection").get("connection").get("display_name"))

# get actions for the connection
print(client.list_actions("servicenow-connection"))

# get action inputs for the action
print(client.list_action_inputs("servicenow-connection", "add-comment-in-servicenow-task"))

result = client.connection("servicenow-connection").actions().execute("add-comment-in-servicenow-task", {
    "input": {
        "parentId": "1234567890",
        "body": "This is a test comment",
    }
})

print(result)
if result.get("job_id"):
    client.get_job_result(str(result["job_id"]))

# Same calls via fluent: client.connection("crm-prod").actions().execute("fetch-deal", {...})

client.close()
```

Request/response JSON uses **`snake_case`**. Failures raise **`ConnectionsApiError`** (`status_code`, `body`).

---

## Method reference

### Errors and lifecycle

| Item | Notes |
|------|--------|
| **`ConnectionsApiError`** | Raised on HTTP ≥ 400 or bad JSON. **`status_code`**, **`body`**. |
| **`client.close()`** | Close the default internal **httpx** client. |
| **Context manager** | `with ConnectionsClient(...) as c:` calls **`close()`** on exit. |
| **Custom client** | **`ConnectionsClient(..., http_client=httpx.Client(...))`** or **`from_config(..., http_client=…)`** — you own the client’s lifetime. |

### `ConnectionsClientConfig` (optional headers)

| Field | Sent as header (when set) |
|-------|---------------------------|
| **`base_url`** | Origin only; client calls **`{base_url}/api/v1/...`**. |
| **`service_token`** | **`X-Service-Token`**. |
| **`csrf_token`** | **`X-CSRF-Token`**. |
| **`timeout_seconds`** | httpx read/connect timeout. |
| **`extra_headers`** | Merged last (e.g. **`Cookie`**). |

### Client construction

| Method | Purpose |
|--------|---------|
| **`ConnectionsClient(base_url, service_token="", *, http_client=None)`** | Simple integrator ctor. |
| **`ConnectionsClient.from_config(ConnectionsClientConfig, *, http_client=None)`** | Full config — see [Local development](#local-development-without-a-service-token-cookies--csrf). |

### Fluent roots (same HTTP as flat helpers)

| Fluent | HTTP |
|--------|------|
| **`client.jobs().result(job_id)`** | **`GET /jobs/{job_id}`** |
| **`client.connections().list(relay_id=None, *, authorized=None)`** | **`GET /connections`** + optional **`relay_id`**, **`authorized=true`** |
| **`client.actions_catalog().list()`** | **`GET /actions`** (tenant-wide catalog; not per-connection) |
| **`client.connection(slug)`** | Scope for one connection — see below |

### Jobs

| Flat | Fluent |
|------|--------|
| **`get_job_result(job_id)`** | **`jobs().result(job_id)`** |

### Connections

| Flat | Fluent (`connection(slug)`) | HTTP |
|------|----------------------------|------|
| **`list_connections(relay_id=None, *, authorized=None)`** | **`connections().list(...)`** | **`GET /connections`** |
| **`get_connection(slug)`** | **`get()`** | **`GET /connections/{slug}`** |
| **`authorize_connection(slug)`** | **`authorize()`** | **`POST /connections/{slug}/authorize`** body **`{}`** |
| **`unauthorize_connection(slug)`** | **`unauthorize()`** | **`POST /connections/{slug}/unauthorize`** body **`{}`** |
| **`toggle_connection_active(slug, active)`** | **`set_active(active)`** | **`POST /connections/{slug}/toggle-active`** body **`{"active": bool}`** |

### Actions — read (catalog vs connection)

| Flat | Fluent | HTTP |
|------|--------|------|
| **`list_all_actions()`** | **`actions_catalog().list()`** | **`GET /actions`** |
| **`list_actions(connection_slug)`** | **`actions().list()`** | **`GET /connections/{slug}/actions`** |
| **`get_action(connection_slug, action_slug)`** | **`actions().get(action_slug)`** | **`GET /connections/{slug}/actions/{action_slug}`** |
| **`list_action_inputs(connection_slug, action_slug)`** | **`actions().list_inputs(action_slug)`** | **`GET /connections/{slug}/actions/{action_slug}/inputs`** |

### Saved action execute

| Flat | Fluent |
|------|--------|
| **`execute_action(connection_slug, action_slug, body=None, *, async_=False, timeout_ms=None)`** | **`connection(slug).actions().execute(action_slug, body=None, *, async_=False, timeout_ms=None)`** |

- **HTTP:** **`POST /connections/{slug}/actions/{action_slug}/execute`** with optional query **`async=true`**, **`timeout_ms=<int>`** (same rules as typed executors below).
- **Body:** maps to JSON keys **`input`**, **`options`** (and any other keys the server accepts). Use **`list_action_inputs`** to discover **`input`** field names.

### POST query combinations (async + timeout)

These apply to **saved action execute** and **every** typed HTTP / file / SQL **`POST`** below. Valid combinations:

| `async_` | `timeout_ms` | Query string |
|----------|----------------|--------------|
| `False` | `None` | *(none)* |
| `True` | `None` | **`?async=true`** |
| `False` | `5000` | **`?timeout_ms=5000`** |
| `True` | `5000` | **`?async=true&timeout_ms=5000`** |

Async responses may include **`job_id`** → poll **`get_job_result`**.

### Typed HTTP (same `parameters`, `async_`, `timeout_ms` on every row)

**`parameters`** typically includes **`path`**, **`query`**, **`headers`**, **`body`** (see [api-reference.md](../docs/api-reference.md)).

| Flat | Fluent | Path (under **`/api/v1/connections/{slug}`**) |
|------|--------|-----------------------------------------------|
| **`execute_http_get(...)`** | **`http().get(...)`** | **`POST .../http/get`** |
| **`execute_http_post(...)`** | **`http().post(...)`** | **`POST .../http/post`** |
| **`execute_http_patch(...)`** | **`http().patch(...)`** | **`POST .../http/patch`** |
| **`execute_http_put(...)`** | **`http().put(...)`** | **`POST .../http/put`** |
| **`execute_http_delete(...)`** | **`http().delete(...)`** | **`POST .../http/delete`** |

Each flat signature: **`(connection_slug, parameters=None, *, async_=False, timeout_ms=None)`**. Each fluent: **`(parameters=None, *, async_=False, timeout_ms=None)`**.

### Filesystem (FS connections)

| Flat | Fluent | Path suffix |
|------|--------|-------------|
| **`execute_file_read_file`** | **`file().read`** | **`/file/readFile`** |
| **`execute_file_upload_file`** | **`file().upload`** | **`/file/uploadFile`** |
| **`execute_file_append_file`** | **`file().append`** | **`/file/appendFile`** |
| **`execute_file_list_files`** | **`file().list_files`** | **`/file/listFiles`** |
| **`execute_file_rename_file`** | **`file().rename`** | **`/file/renameFile`** |
| **`execute_file_move_file`** | **`file().move`** | **`/file/moveFile`** |
| **`execute_file_delete_file`** | **`file().delete`** | **`/file/deleteFile`** |

Same **`async_`**, **`timeout_ms`** as HTTP table.

### SQL (SQL connections)

| Flat | Fluent | Path suffix |
|------|--------|-------------|
| **`execute_sql_query`** | **`sql().query`** | **`/sql/query`** |
| **`execute_sql_select`** | **`sql().select`** | **`/sql/select`** |
| **`execute_sql_insert`** | **`sql().insert`** | **`/sql/insert`** |
| **`execute_sql_update`** | **`sql().update`** | **`/sql/update`** |
| **`execute_sql_delete`** | **`sql().delete`** | **`/sql/delete`** |
| **`execute_sql_execute`** | **`sql().execute`** | **`/sql/execute`** *(raw execute; not saved actions)* |

Same **`async_`**, **`timeout_ms`** as HTTP table. Parameter shapes: [api-reference.md](../docs/api-reference.md).

### Full flat → fluent equivalence (checklist)

Every **`execute_*`** row above is **`client.connection(slug).<executor>().<verb>(parameters, async_=…, timeout_ms=…)`**. **`list_*`** / **`get_*`** / lifecycle methods either have the fluent shown in the tables or are only on **`connection(slug)`** / **`actions_catalog()`** / **`connections()`** / **`jobs()`**.

---

## Local development without a service token (cookies + CSRF)

```python
from facilio_connections_sdk import ConnectionsClient, ConnectionsClientConfig

cfg = ConnectionsClientConfig(
    base_url="http://localhost:8081",
    service_token=None,
    csrf_token="paste-fc-csrfToken-cookie-value",
    extra_headers={
        "Cookie": "JSESSIONID=...; fc.idToken.connections=...; fc.csrfToken=...",
    },
    timeout_seconds=120.0,
)

client = ConnectionsClient.from_config(cfg)
```


