Skip to main content

:::note Generated reference Generated from honeyframeapi 0.1.8 — do not edit by hand. :::

honeyframeapi.client

The Honeyframe SDK entry point.

HoneyframeClient is constructed once with a base URL + credentials, then navigates to resource handles (Project, Dataset, Dashboard).

import os
import honeyframeapi
client = honeyframeapi.HoneyframeClient(
"https://platform.your-domain.com",
token=os.environ["HONEYFRAME_TOKEN"], # an hf_… Personal Access Token
project_id=1)
df = client.sql("SELECT * FROM marts.fact_orders FETCH FIRST 100 ROWS ONLY")

For interactive use, username= plus password=getpass.getpass() also works; never hard-code a password in a script.

class HoneyframeClient​

HoneyframeClient(base_url: Optional[str] = None, *, token: Optional[str] = None, username: Optional[str] = None, password: Optional[str] = None, auth: Optional[AuthBase] = None, org_id: Optional[int] = None, project_id: Optional[int] = None, timeout: Optional[float] = DEFAULT_TIMEOUT, verify: Union[bool, str, ssl.SSLContext] = True, max_retries: int = DEFAULT_MAX_RETRIES, retry_backoff: float = DEFAULT_RETRY_BACKOFF, allow_insecure_http: Optional[bool] = None, transport: Optional[httpx.BaseTransport] = None)

Authenticated HTTP client + factory for Honeyframe resource handles.

Create a client.

base_url must be https://. Plain http:// is accepted only for a loopback host (localhost, 127.0.0.1, ::1) or when allow_insecure_http=True (or HONEYFRAME_ALLOW_INSECURE_HTTP=1 in the environment); otherwise HoneyframeConfigError, because the bearer token and any login password would travel in clear text.

verify is True (system trust store), a path to a CA bundle file or directory (for a private CA), or an ssl.SSLContext. verify=False turns certificate checks off and warns.

timeout is the per-request default in seconds (None = no timeout); most calls also take their own timeout=. transport plugs in a custom httpx.BaseTransport (a test double, a proxy transport). Redirects are never followed, so the Authorization header cannot be forwarded to another host.

HoneyframeClient.from_env()​

@classmethod
from_env(**overrides) -> HoneyframeClient

Build a client entirely from environment variables.

Reads HONEYFRAME_URL/HUB_API_BASE, then the auth + project env vars resolved by auth.auth_from_kwargs. Any keyword overrides win.

HoneyframeClient.close()​

close() -> None

HoneyframeClient.using()​

using(*, org_id: Optional[int] = None, project_id: Optional[int] = None) -> HoneyframeClient

Mutate the org/project scope in place and return self (chainable).

HoneyframeClient.request()​

request(method: str, path: str, *, params: Optional[dict] = None, json: Any = None, headers: Optional[dict] = None, project_id: Optional[int] = None, org_id: Optional[int] = None, raw: bool = False, timeout: Any = _DEFAULT, **kw: Any) -> Any

Call any platform endpoint that has no typed method yet.

The supported escape hatch: same auth, org/project headers, retries, 401 re-login and typed exceptions as every handle method:

client.request("GET", "/api/version")
client.request("POST", "/api/some/endpoint", json={...}, timeout=300)

path is relative to base_url and must start with /; an absolute URL is refused so the token never goes to another host. Interpolate untrusted values into path yourself with care (they are NOT encoded here). Extra keyword arguments (files=, data=, content=) go to httpx.Client.request. Returns the decoded JSON body (or bytes with raw=True).

HoneyframeClient.stream_chat()​

stream_chat(message: str, *, agent_id: Optional[int] = None, session_id: Optional[int] = None, model: Optional[str] = None, persona: Optional[str] = None, system: Optional[str] = None, webapp_key: Optional[str] = None, page_key: Optional[str] = None, history: Optional[list] = None, images: Optional[list] = None, max_tokens: Optional[int] = None, project_id: Optional[int] = None, org_id: Optional[int] = None) -> Iterator[dict]

Stream a chat reply from POST /api/chat/stream as SSE events.

Yields {"event", "data"} dicts in the Honeyframe SSE schema: token / thinking / tool_start / tool_result / citation / artifact / usage / error / done. Render token text as it arrives, or fold the whole stream with collect_stream:

for ev in client.stream_chat("Top 5 branches by revenue?", persona="director"):
if ev["event"] == "token":
print(ev["data"]["text"], end="", flush=True)

persona selects a capability persona (e.g. director = governed marts-only); it is intersected server-side with the caller's scopes, so it can only narrow, never escalate.

images attaches pictures for a vision-capable model — a list of content parts in the same shape the web/mobile clients send:

images=[{"type": "image_url",
"image_url": {"url": "data:image/png;base64,iVBORw0K..."}}]

Ignored server-side when the resolved model is not vision-capable.

HoneyframeClient.get_auth_info()​

get_auth_info() -> dict

Return the current user profile (GET /api/auth/me).

HoneyframeClient.license_status()​

license_status() -> dict

License state for the caller's current org (GET /api/license/status).

Returns {"status": …} with status ∈ valid | grace | expired | missing | invalid. Only valid and grace pass the platform's lockdown gate — in every other state each endpoint outside /api/license/* returns 403, so this is the one call worth making first when a whole script starts failing with auth errors.

When a license resolves, the dict also carries customer, tier, products, users_limit, max_seats, features, expires, days_remaining, version and org_slug. grace / expired / missing / invalid add a human-readable message.

HoneyframeClient.create_pat()​

create_pat(name: str = '', *, expires_days: Optional[int] = PAT_DEFAULT_DAYS) -> dict

Mint an hf_… Personal Access Token.

The full secret is in the returned dict's token field — shown ONCE. Store it, then authenticate future clients with HoneyframeClient(url, token="hf_…").

expires_days defaults to 90; 0..730 is accepted and 0 means the token never expires (opt in deliberately). None sends no lifetime, so the platform applies its own default (90 days).

HoneyframeClient.list_pats()​

list_pats() -> list[dict]

List your active PATs (metadata only — never the secret).

HoneyframeClient.plugin_recipe_types()​

plugin_recipe_types() -> list[dict]

Custom recipe types contributed by the plugins your org has enabled (GET /api/plugins/recipe-types). Each entry: {type, plugin, display_name, description, params, standalone}. Empty when no plugins are enabled. Pass a type to create_plugin_recipe.

HoneyframeClient.revoke_pat()​

revoke_pat(token_id: int) -> dict

Revoke one of your PATs.

HoneyframeClient.get_instance_info()​

get_instance_info() -> dict

Return the platform version (GET /api/version).

HoneyframeClient.register_node()​

register_node(name: str, base_url: str, api_key: str, *, role: str = 'automation') -> dict

Register a remote Honeyframe install (base_url + a PAT issued on that install) so a bundle can be pushed to it. The PAT is encrypted at rest and never returned. Returns {node_id, name, base_url, role}.

HoneyframeClient.list_nodes()​

list_nodes() -> list[dict]

List registered remote nodes (secrets never included).

HoneyframeClient.delete_node()​

delete_node(node_id: int) -> dict

Delete a registered remote node.

HoneyframeClient.list_projects()​

list_projects() -> list[dict]

List projects visible to the current user.

HoneyframeClient.get_project()​

get_project(project: Union[int, str]) -> Project

Return a Project handle by numeric id or slug.

A slug is resolved against list_projects (matching slug or name); an int is used directly.

HoneyframeClient.create_project()​

create_project(name: str, slug: str, *, description: Optional[str] = None, icon: str = 'folder', color: str = '#B45309') -> Project

Create a project and return its handle.

HoneyframeClient.list_dashboards()​

list_dashboards(tab: str = 'all', *, project_id: Optional[int] = None) -> list[dict]

List dashboards (tab ∈ my|shared|all|public).

Scoped to the client's current project; pass project_id to list another project's (the server checks you can read it).

HoneyframeClient.get_dashboard()​

get_dashboard(dashboard_id: int) -> Dashboard

Return a Dashboard handle (fetches detail + cards).

HoneyframeClient.list_card_templates()​

list_card_templates() -> list[CardTemplate]

The org's reusable card templates as CardTemplate handles (org-visible ∪ the caller's private ones).

HoneyframeClient.create_card_template()​

create_card_template(name: str, card_type: str, *, sql: str = '', card_config: Optional[dict] = None, description: Optional[str] = None, size_x: int = 12, size_y: int = 4, tags: Optional[list] = None, folder: Optional[str] = None, visibility: Optional[str] = None) -> CardTemplate

Create a reusable card template. visibility ∈ org | private (default org). Returns its CardTemplate handle.

HoneyframeClient.list_collections()​

list_collections() -> list[dict]

Dashboard collections in the current org (each with dashboard_count).

HoneyframeClient.create_collection()​

create_collection(name: str, *, parent_id: Optional[int] = None) -> dict

Create a dashboard collection. parent_id nests it under another.

HoneyframeClient.update_collection()​

update_collection(collection_id: int, name: str, *, parent_id: Optional[int] = None) -> dict

Rename / re-parent a collection.

HoneyframeClient.delete_collection()​

delete_collection(collection_id: int) -> dict

Delete a collection; its dashboards fall back to uncategorized.

HoneyframeClient.list_connectors()​

list_connectors(category: Optional[str] = None) -> list[dict]

List configured connectors for the current org.

HoneyframeClient.list_connector_catalog()​

list_connector_catalog() -> list[dict]

List the connector types available to configure.

HoneyframeClient.get_connector()​

get_connector(connector_id: int) -> Connector

Return a Connector handle.

HoneyframeClient.create_connector()​

create_connector(name: str, connector_type: str, *, config: Optional[dict] = None, description: str = '', output_schemas: Optional[list] = None) -> Connector

Create an org-level connector and return its handle.

HoneyframeClient.list_my_credentials()​

list_my_credentials() -> list[dict]

The caller's personal credential slots across every per_user-mode connector in the org, each with fill status and its secret fields ({connector_id, name, connector_type, filled, updated_at, secret_fields}). Fill a slot with Connector.set_my_credentials.

HoneyframeClient.list_knowledge_bases()​

list_knowledge_bases() -> list[dict]

Knowledge Banks visible in the current project (this project's ∪ the org-level ones), each with doc/chunk counts.

HoneyframeClient.get_knowledge_base()​

get_knowledge_base(kb_id: int) -> KnowledgeBase

Return a KnowledgeBase handle (fetches its record).

HoneyframeClient.create_knowledge_base()​

create_knowledge_base(name: str, *, description: str = '', embedding_model: str = 'text-embedding-3-small', embedding_dimensions: int = 1536, chunk_size: int = 800, chunk_overlap: int = 100, source_folder_id: Optional[int] = None, vector_connector_id: Optional[int] = None, embedding_connector_id: Optional[int] = None) -> KnowledgeBase

Create a Knowledge Bank in the current project and return its handle.

vector_connector_id picks the vector store that holds the embeddings (faiss / chroma / pinecone / pgvector / the built-in numpy store); embedding_connector_id picks the embedding provider (openai / ollama / gemini). Both are optional — a KB with neither stores chunks but can't be searched until wired + embedded. Discover the eligible connectors with kb_connector_options.

HoneyframeClient.kb_connector_options()​

kb_connector_options() -> dict

Which of the org's connectors can back a Knowledge Bank — {vector_stores: [...], embedding_providers: [...]}. Derived from the connector registry, so new backends (e.g. pgvector) appear automatically.

HoneyframeClient.llm_mesh_overview()​

llm_mesh_overview() -> dict

Every LLM connection in the org joined with its governance policy and month-to-date spend/calls, plus org-wide totals + the monthly budget — {connections: [{connector_id, name, connector_type, provider, default_model, mtd_spend_usd, mtd_calls, policy, budget_state}], totals, org_monthly_budget_usd}.

HoneyframeClient.get_llm_policy()​

get_llm_policy(connector_id: int) -> dict

The governance policy for one LLM connection (defaults + configured: false when unset).

HoneyframeClient.set_llm_policy()​

set_llm_policy(connector_id: int, *, allowed_models: Optional[list] = None, monthly_budget_usd: Optional[float] = None, budget_blocking: bool = False, cache_enabled: bool = True, max_parallelism: Optional[int] = None, usable_by: str = 'all') -> dict

Upsert an LLM connection's governance policy. allowed_models=[] (or None) = all models; monthly_budget_usd=None = no quota (budget_blocking=False → warn-only, True → hard-stop over budget); max_parallelism=None = unlimited; usable_by ∈ all | admins. Needs org admin.

HoneyframeClient.llm_mesh_usage()​

llm_mesh_usage(*, days: int = 30) -> dict

Windowed LLM spend roll-up for the org — per-connection, per-model, and per-day ({days, by_connector, by_model, daily}). days is clamped server-side to 1–365.

HoneyframeClient.list_meanings()​

list_meanings() -> list[dict]

The org's semantic-type registry — platform built-ins ∪ the org's own meanings, priority-ordered. Built-ins carry org_id: null and are read-only.

HoneyframeClient.create_meaning()​

create_meaning(name: str, label: Optional[str] = None, *, detector: str = 'pattern', name_pattern: Optional[str] = None, value_pattern: Optional[str] = None, values_list: Optional[list] = None, db_types: Optional[list] = None, mask_strategy: Optional[str] = None, sensitivity: Optional[str] = None, priority: Optional[int] = None) -> dict

Register a tenant meaning (e.g. customer_id with a name_pattern + a value_pattern for conformance). detector ∈ pattern | values | type. Returns the new meaning. Needs org admin; 409 on a duplicate name.

HoneyframeClient.update_meaning()​

update_meaning(meaning_id: int, **fields) -> dict

Edit a tenant meaning (its name is immutable). 403 on a built-in.

HoneyframeClient.delete_meaning()​

delete_meaning(meaning_id: int) -> dict

Deactivate a tenant meaning. 403 on a built-in.

HoneyframeClient.list_code_environments()​

list_code_environments() -> list[dict]

The org's managed Python code environments.

Each row carries build_state — not_built | building | built | stale | failed — derived from the row AND the venv on disk, so it is the field to branch on. status is the raw column and can say ready for an env whose tree was wiped.

HoneyframeClient.code_environment_build_availability()​

code_environment_build_availability() -> dict

{enabled, reason, sandbox_user} — whether this install can build a code env at all, and what is missing when it cannot. Builds run under the recipe sandbox, so the sandbox account is the precondition.

HoneyframeClient.get_code_environment()​

get_code_environment(env_id: int) -> dict

One code environment. 404 when it is not this org's.

HoneyframeClient.create_code_environment()​

create_code_environment(name: str, *, python_version: str = '3.11', packages: Optional[list] = None, description: Optional[str] = None, allow_source_builds: bool = False) -> dict

Declare a code environment (org admin).

packages are PEP 508 specs, optionally hash-pinned (pandas==2.1.0 --hash=sha256:…); a malformed spec is rejected here, not at build time. allow_source_builds turns OFF the default wheels-only install — leave it False unless a package has no wheel.

HoneyframeClient.update_code_environment()​

update_code_environment(env_id: int, **fields) -> dict

Edit a code environment (org admin). Editing the manifest of a BUILT env leaves the venv in place and marks it stale until rebuilt.

HoneyframeClient.delete_code_environment()​

delete_code_environment(env_id: int) -> dict

Delete a code environment and its materialized venv (org admin).

HoneyframeClient.validate_code_environment()​

validate_code_environment(env_id: int) -> dict

PEP 508-parse every spec; returns {env, results, ok}. Installs nothing.

HoneyframeClient.code_environment_build_log()​

code_environment_build_log(env_id: int) -> dict

{status, build_state, stale, materialized, build_log, …} — the poll surface while a build runs.

HoneyframeClient.build_code_environment()​

build_code_environment(env_id: int, *, wait: bool = False, timeout: int = 1800, poll_interval: float = 3.0) -> dict

Materialize the environment as a real venv, under the recipe sandbox.

Returns the router's {env, started, materialized, message} immediately. started=False means builds are unavailable on this install and message says what is missing — it is NOT a failure to raise on, and nothing was built.

wait=True polls /build-log until the build leaves building and returns that final payload (build_state is built / stale / failed); it raises TimeoutError if the build is still running after timeout seconds — the build itself keeps going server-side.

HoneyframeClient.list_assets()​

list_assets(*, asset_type: Optional[str] = None, status: Optional[str] = None, project_id: Optional[int] = None, scope: Optional[str] = None) -> list[dict]

List published assets, optionally filtered.

HoneyframeClient.get_asset()​

get_asset(asset_id: int) -> PublishedAsset

HoneyframeClient.create_asset()​

create_asset(asset_type: str, asset_key: str, title: str, *, description: str = '', config: Optional[dict] = None, theme: Optional[dict] = None, roles: Optional[list] = None, is_public: bool = False, icon: str = '', sort_order: int = 0) -> PublishedAsset

Create a published asset (dashboard|chat_agent|data_api|form|…).

HoneyframeClient.list_webapps()​

list_webapps() -> list[dict]

List webapps in the current org (GET /api/webapps).

HoneyframeClient.get_webapp()​

get_webapp(key: str) -> Webapp

Return a Webapp handle by asset_key (fetches its config).

HoneyframeClient.webapp_capabilities()​

webapp_capabilities() -> dict

Discover, programmatically, what the webapp engine can build — block kinds + their schemas, the sandbox/game contract, card types, layout, and limits (GET /api/webapps/capabilities).

Read this instead of hardcoding assumptions: it tells you that a sandboxed html block runs arbitrary canvas/WebGL JS (so you can build games), the exact size/SQL limits, and what window.hf exposes inside the iframe. The same self-description feeds the natural-language builder (Webapp.ai_edit), so the engine and the AI agree on what's possible.

caps = client.webapp_capabilities()
caps["block_kinds"] # card / code / html + examples
caps["block_kinds"][2]["sandbox"]["can"] # what a game block may do
caps["limits"]["max_html_block_chars"] # inline budget for a game

HoneyframeClient.publish_webapp()​

publish_webapp(asset_key: str, title: str, *, config: Optional[dict] = None, description: str = '', theme: Optional[dict] = None, roles: Optional[list] = None, is_public: bool = False, icon: str = '', sort_order: int = 0, publish: bool = False) -> Webapp

Create a webapp asset and return its Webapp handle.

Webapps are project-scoped — the client must have project_id set (it's sent as X-Project-Id), or the server rejects it. config carries the page/nav/filter layout (card_ref blocks point at dashboard cards; html/code blocks are inline).

⚠️ This creates a draft by default — the webapp viewer (/apps/<key>) only serves published assets. Pass publish=True (or call Webapp.publish) to make it live. See create_webapp for a builder-friendly creator.

HoneyframeClient.create_webapp()​

create_webapp(asset_key: str, title: str, *, pages: Optional[list] = None, nav: Optional[list] = None, filters: Optional[dict] = None, chrome: Optional[dict] = None, description: str = '', theme: Optional[dict] = None, roles: Optional[list] = None, is_public: bool = False, icon: str = '', publish: bool = False) -> Webapp

Create a webapp from page/nav builders in one call.

pages is a list from page (blocks from card_ref / html_block / code_card); nav from nav_item. Set publish=True to make it live at /apps/<asset_key> immediately. Idempotency is the caller's job — use a fresh asset_key or Webapp.update to edit an existing one.

HoneyframeClient.get_api_service()​

get_api_service(asset_id: int) -> APIService

Return an APIService handle (fetches its config).

HoneyframeClient.create_api_service()​

create_api_service(asset_key: str, title: str, *, endpoints: Optional[list] = None, publish: bool = False, description: str = '', roles: Optional[list] = None, is_public: bool = False, icon: str = '', project_id: Optional[int] = None) -> APIService

Create a multi-endpoint API service and return its handle.

endpoints is a list from sql_endpoint / lookup_endpoint / model_endpoint. API services are project-scoped — the client must have project_id set (or pass it), else the server rejects it. Creates a draft; pass publish=True to make the endpoints callable immediately.

HoneyframeClient.list_agents()​

list_agents() -> dict

Agent library ({pinned, enterprise, project, recent_conversations}).

HoneyframeClient.get_agent()​

get_agent(agent_id: int) -> Agent

Return an Agent handle bound to a published agent id.

HoneyframeClient.chat()​

chat(message: str, *, agent_id: Optional[int] = None, session_id: Optional[int] = None, model: Optional[str] = None, webapp_key: Optional[str] = None, page_key: Optional[str] = None) -> dict

Send a chat message (optionally to a specific agent_id).

webapp_key (with optional page_key) auto-grounds a SQL-mode agent in that webapp's dashboard cards — the same embedded-assistant grounding the webapp viewer applies, exposed for programmatic use.

HoneyframeClient.send_push()​

send_push(title: str, body: str, *, user_ids: Optional[list] = None, role: Optional[str] = None, data: Optional[dict] = None) -> dict

Send a push notification to users by id and/or role (admin only).

Targets the registered mobile devices of the given users (and/or every user with role) and returns {sent, pruned, total, users}. The primitive behind proactive notifications — e.g. a scheduled director briefing pushing role="director". Requires an admin/superadmin token.

HoneyframeClient.list_datasets()​

list_datasets(**filters: Any) -> list[dict]

List datasets in the current project (requires project_id set).

HoneyframeClient.get_dataset()​

get_dataset(name: str) -> Dataset

Return a Dataset handle in the current project.

HoneyframeClient.ai_search_datasets()​

ai_search_datasets(intent: str, *, project_id: Optional[int] = None, tags: Optional[list] = None, limit: int = 10) -> dict

Rank datasets by relevance to a natural-language intent.

POST /api/datasets/ai-search — the same catalog-discovery ranking the dashboard chat agent calls as a tool. project_id=None (the default) searches across every project in the caller's org; pass a project_id to confine it to one (the server 404s a project outside your org). tags filters candidates before ranking; limit caps the result list.

Returns {"results": [...], "intent": ..., "count": n}. Needs project.edit; org admins see beyond the currently-pinned project.

HoneyframeClient.register_source_table()​

register_source_table(schema_name: str, table_name: str, *, connector_id: Optional[int] = None, friendly_name: str = '', name: Optional[str] = None) -> Dataset

Register a raw table as a source_table dataset in the current project.

HoneyframeClient.register_schema()​

register_schema(schema_name: str, *, connector_id: int, search: str = '') -> list[Dataset]

Register every table in a connector schema in the current project.

HoneyframeClient.sql()​

sql(query: str, *, connector_id: Optional[int] = None, row_limit: int = 10000, params: Optional[dict] = None) -> Any

Run ad-hoc SQL in the current project and return a DataFrame.

The headline analyst path — one call from SQL to a DataFrame. Requires project_id to be set on the client (pass it at construction or via using). params are named binds (WHERE d >= :p_start with params={"p_start": "2026-01-01"}). See Project.sql for truncation.

Constants​

NameValue
DEFAULT_TIMEOUT60.0
PAT_DEFAULT_DAYS90
PAT_MAX_DAYS730
DEFAULT_MAX_RETRIES2
DEFAULT_RETRY_BACKOFF0.5
INSECURE_HTTP_ENV'HONEYFRAME_ALLOW_INSECURE_HTTP'

Verified against honeyframeapi 0.1.8.