# Overview Source: https://docs.usefini.com/en/api-reference/actions Define typed API calls your AI agent can invoke mid-conversation to cancel orders, look up records, update accounts, and trigger workflows. An **Action** is a unit of work your agent can perform on behalf of a user mid-conversation: skip a payment, cancel a card, reorder a card, update a phone number, look up an order. The UI labels this page **External Actions**, *"Set up API calls that your AI agent can perform on behalf of users."* External Actions page in the Fini Demo workspace showing GetTransactions and GetBalance actions, field counts, the New Action button, and an inline notice linking to Rules Actions are deterministic, they do the work, they don't decide *when* to do it. That decision lives in the [Rulebook](/en/automations/rulebook), a behavior tree that matches user intent and routes to the right Action. An Action does nothing on its own. The product says it plainly: *"Actions run only when a rule invokes them — connect each action as a step in an intent or business rule."* Wire it via **Rulebook → Add a step → Select "Tool" → Choose your action**. An Action with no Tool node referencing it is an orphan, it exists but no agent will ever invoke it. For a walkthrough showing how Actions plug into Attributes, Rulebook, and Reply Behavior end-to-end, see [End-to-end: cancellation flow](/en/walkthroughs/cancellation-flow). For database and warehouse lookups, see [Database and Warehouse Connections](/en/api-reference/database-warehouses). ## How Actions relate to the Rulebook The Rulebook is the brain; Actions are the hands. When the Rulebook walks its tree and reaches a **Tool** node, it invokes the Action that node points to: ```mermaid theme={null} --- title: Where an Action runs --- flowchart LR MSG["Customer
message"] --> RB["Rulebook
matches intent"] RB --> READ["Read node
extracts inputs"] READ --> TOOL["Tool node
invokes the Action"] TOOL --> ACT["Action runs
its Data Steps"] ACT --> OUT["Typed output
back into the tree"] OUT --> REPLY["Reply node
uses the output"] ``` The Action owns only the middle: take typed inputs, call your APIs, return typed outputs. Intent matching, input extraction, branching, and the final reply are all the Rulebook's job. This separation is why an Action's description doesn't affect *whether* it fires, routing is encoded in the tree's structure, not in the Action. ## Actions vs Attributes Both are built on the same Data Steps engine, but they trigger differently: | | [Attributes](/en/api-reference/attributes) | Actions | | --------------- | ----------------------------------------------- | ------------------------------------------------------------------- | | When it runs | Every chat message, automatically. | When a Tool node in the [Rulebook](/en/automations/rulebook) fires. | | Mental model | Context the agent always has. | A unit of work the agent performs on request. | | Source | Required (UI / Widget / connected integration). | None, Actions are source-agnostic. | | Shape | Available Data fields with three switches each. | Explicit input and output fields. | | Typical example | "Get the customer's plan and recent orders." | "Cancel the customer's subscription." | Rule of thumb: if context is needed on *every* reply, it's an Attribute. If it's only needed when the customer asks for it, and especially if it has side effects, it's an Action. ## Anatomy of an action The detail view has two tabs: **Setup** and **Data Steps**. ### Setup tab Two sections, named exactly as the UI labels them: * **Required information for this action to run**, the input fields. Each field has a name, a type (`string` / `number` / `boolean`), and a `required` flag. These define the contract the Rulebook must satisfy before invoking the Tool node, typically by placing a **Read** node upstream (LLM extraction) or referencing context already on the conversation (such as an Attribute). * **Data returned after this action runs**, the output fields, each with a name and type. These flow back into the tree for downstream **Check** nodes to branch on, **Reply** nodes to interpolate, and other **Tool** nodes to consume as input. Setup tab showing a required string input under Required information, and boolean and string fields under Data returned after this action runs ### Data Steps tab The chain of HTTP requests that takes the inputs, calls your APIs, and produces the outputs, the same engine as [Attributes' Data Collection Steps](/en/api-reference/attributes#attributes-from-external-systems). If the data lives in a warehouse such as Redshift, put a scoped HTTPS endpoint in front of it rather than connecting the Action directly to the database. | Field | What it does | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Step Name** + **Method** | A label, and the HTTP verb (GET / POST / PUT / PATCH / DELETE). | | **URL** | The endpoint. Type `$` to insert a dynamic value. | | **Headers** / body | JSON. Reference an input field by name with the `$` picker, for example, an input field interpolated into the URL, an API key in an `Authorization` header. | | **Save From Response** | The response fields to keep: your field name on the left, the response's JSON path on the right. | Below the steps, a **Connect values to the fields that will be returned** panel maps each declared output field to a value a step produced (`Field` → `Gets value from`: `Step → response field`). Data Steps tab: one HTTP step with Step Name, Method, URL, Headers and Save From Response, plus the Connect values panel mapping each output field ## Creating an action Land on **API Setup → Actions** in the sidebar. The list shows every action in the workspace with its field count. * **Name** (required): an imperative phrase, *Skip Smart Save*, *Cancel Plastic Card*, *Reorder Physical Card*. * **Description**: a human-readable summary for teammates browsing the list. It does **not** trigger the action; routing lives in the [Rulebook](/en/automations/rulebook). Create New Action dialog showing Action Name, Description, Cancel, and Create Action controls Under **Required information for this action to run**, list every field the action needs. Mark a field `required` when the action cannot proceed without it. Once the Rulebook routes a conversation here, the LLM extracts these from context (or asks the customer for any required field it can't find). Under **Data returned after this action runs**, list every field the action returns. Downstream Reply and Check nodes read these, e.g. a `success` boolean and a `message` string. Add one or more HTTP requests that take the inputs and produce the outputs. Use the `$` picker to interpolate input fields into URLs, headers, or bodies. Then, in **Connect values to the fields that will be returned**, map each output field to a step's response value. Click the **Play** button at the top of the detail view. Provide sample inputs, run the chain, and verify the response matches the outputs you declared. Click **Save**. The action now exists in the workspace but **still won't run**. Open the [Rulebook](/en/automations/rulebook), add a Tool node pointing at this action under a rule that describes the triggering intent, and publish. The rule's agent assignments decide which agents can invoke it. ## A worked example: cancel subscription A canonical action. The customer says "I want to cancel my plan", a Rulebook rule matches the cancellation intent and invokes this action, the action calls your billing API, and a Reply node confirms. **Name:** "Cancel Subscription". **Description:** "Cancels the customer's active subscription via the billing API. Returns confirmation id, refund amount, and effective date." (For the team to read; not what triggers it.) The customer's unique identifier. Typically already on the conversation from a [User Attribute](/en/api-reference/attributes) lookup, so the upstream Read node rarely has to ask the customer for it. Why the customer is cancelling. The agent collects this only if the customer volunteers one, leave optional rather than forcing extraction. The billing system's confirmation reference for this cancellation. Interpolated into the agent's confirmation reply. The refund amount in your billing currency. Surface this to the customer so they know what to expect. ISO 8601 date the cancellation takes effect, typically the next billing date. A downstream Reply node uses these to compose the confirmation: *"Your subscription was cancelled, a refund of \$X will arrive by \[date]."* **Step Name:** *Cancel via Billing API*. **Method:** `POST`. **URL:** the cancellation endpoint on your billing API, with the `customerId` input interpolated into the path via the `$` picker. **Headers:** an `Authorization` header carrying your billing token. **Body:** a JSON object containing `reason`, interpolated from the input. **Save From Response:** map the billing API's response fields to your output names, for example, the billing system's `confirmation_id` saves as `confirmationId`, its `refund.amount` saves as `refundAmount`, and its `effective_at` saves as `effectiveDate`. In the panel below the step, map each output to the step's response: `confirmationId ← Cancel via Billing API → confirmationId`, and likewise for `refundAmount` and `effectiveDate`. Run the Test panel with a real `customerId` from your dev environment and confirm the response shape matches your declared outputs. Save, then add a Tool node referencing **Cancel Subscription** under the rule that matches the cancellation intent. Once wired, on a message like *"please cancel my subscription, the product isn't working for us"* the Rulebook walks roughly: the **Steps** root short-circuits to the cancellation branch (its rule description matches the intent); a **Read** node extracts `reason = "the product isn't working for us"`; a **Check** node confirms the customer is identified (`customerId` non-null in context); a **Tool** node invokes **Cancel Subscription**; the `confirmationId` / `refundAmount` / `effectiveDate` outputs flow back; a **Reply** node composes the confirmation. The Action owns only the API call and the typed result, everything else is the Rulebook. ## Chaining actions A single Tool node rarely covers an end-to-end workflow. The common pattern is to chain Tool nodes inside a **Sequence**, each Tool's output feeding the next Tool's input. For example, a refund flow might run: 1. **Lookup Order**, input `orderId`; output `customerId`, `totalAmount`, `isRefundable`. 2. **Verify Eligibility**, input `customerId`, `totalAmount` (from step 1); output `eligible`, `policyReason`. 3. **Submit Refund**, input `customerId`, `amount` (= `totalAmount` from step 1); output `refundId`, `eta`. A **Check** node between steps 2 and 3 can short-circuit on `eligible == false` and route to a Reply node that explains the denial. Because upstream outputs become downstream inputs, define each action's input/output fields precisely, otherwise downstream nodes can't see fields they expected, or pass values that don't match the next Tool's required types. ## Which agents can run an action Actions live at the **workspace level**. Unlike [Attributes](/en/api-reference/attributes#deploying-attributes-for-an-ai-agent), there is no per-agent attachment, you don't toggle which agents an action belongs to. An action becomes effective for an agent entirely through the [Rulebook](/en/automations/rulebook). A rule has agent assignments; if a rule is assigned to an agent and its tree contains a Tool node referencing the action, that agent can trigger it. The same action wired into multiple rules is reachable from every agent those rules are assigned to. So when a new action isn't getting called, the question is *"is there a published rule, assigned to the responding agent, with a Tool node pointing at this action?"*, not *"is this action attached to this agent?"* The public API does expose agent-assignment routes that accept action IDs ([List agent assignments](/en/api-reference/list-action-agents), [Assign to agents](/en/api-reference/assign-action-agents)). These records are stored, but the backend does not check them when a rule invokes an action; at runtime, assignments only gate [Attributes](/en/api-reference/attributes). Creating one never makes an action run, and its absence never blocks one. ## Why an action isn't being called Actions don't self-trigger. Open the [Rulebook](/en/automations/rulebook), find or create a rule with a Tool node pointing at this action, and publish it. This is the most common cause and matches the in-product warning. A rule only runs on agents in its assignment list. Open the rule and confirm the responding agent is selected. The Steps root picked a different branch, or a Check node above the Tool failed. Use the Rulebook test panel to walk an example message through the tree and see which node short-circuits. A Read node upstream may be failing to extract the field, or the context it relies on (such as an Attribute) isn't populated. The Tool node can't fire without every required input. Run the action's **Test** panel with realistic inputs. A 401 (auth expired), 404 (record not found), or a response that doesn't match your Save From Response paths surfaces here. The action runs but downstream Reply / Check nodes read nothing useful. Compare the **Connect values** mappings against an actual API response. ## Deletion Deleting an action also deletes its Data Steps and any links tying it to rules. The action is **irreversible**; the confirmation dialog calls this out. # Overview Source: https://docs.usefini.com/en/api-reference/actions-and-attributes How actions, attributes, and external API calls fit together, plus the shared object schemas the endpoint pages reference. [Actions](/en/api-reference/actions) and [Attributes](/en/api-reference/attributes) are both configured outbound API calls. An **Action** runs when a [Rulebook](/en/automations/rulebook) Tool node invokes it. An **Attribute** runs automatically at the start of a conversation to load context (for example, a `GetUserInfo` lookup). Use these public routes to create, read, update, delete, and test both from your backend, so a workspace can be set up entirely through the API instead of the dashboard. For database and warehouse-backed lookups, Fini still calls an HTTPS endpoint. Put a scoped API in front of Redshift, Snowflake, BigQuery, Postgres, or another warehouse, then configure that endpoint as an external API call. See [Database and Warehouse Connections](/en/api-reference/database-warehouses). The wire-format paths use `/hc-tools` and `/api-function-configs` because that is the current controller contract. In this reference we call them **actions**, **attributes**, and **external API calls** because that is what they represent in the product. An Action and an Attribute are the same resource, distinguished by one field: * `alwaysGet: false`: an **Action**, invoked by a rule. * `alwaysGet: true`: an **Attribute**, fetched automatically each conversation. The list route returns both. Filter on `alwaysGet` to separate them. ## How the pieces fit An action or attribute holds the name, description, and typed input and output schema. Its actual HTTP calls live in one or more **external API call steps** (`api-function-configs`, still called Data Steps in the wire-format object) linked by `toolId` and run in `stepNumber` order, each feeding its extracted output into the next. ```mermaid theme={null} flowchart LR A["Action / Attribute
(name, input + output schema)"] --> S1["External API call 1
HTTP request"] S1 --> S2["External API call 2
HTTP request"] S2 --> OUT["Typed output
(output schema)"] ``` A rule gets nothing back from an Action unless the Action declares an **output schema**. Set `outputSchema` on the action (via [Update action](/en/api-reference/update-action)) and map each output field to an external API call response path. For fields whose `source` is `apiResponse`, use the step-qualified path format `[stepId].[responseMappingKey]` so the dashboard editor can show the field as mapped. ## Setup order Creating a working action or attribute is a short sequence, the same one the dashboard performs: `POST /v2/hc-tools/public` with `name` and `alwaysGet`. `PATCH /v2/hc-tools/{id}/public` with `inputSchema` and `outputSchema`. `POST /v2/api-function-configs/public` with `toolId` set and a `stepNumber`. `POST /v2/hc-tools/junctions/public` to assign the attribute to agents. Attributes only run for assigned agents. For actions, skip this and wire the action into a [Rulebook](/en/automations/rulebook) Tool node instead; action assignments are stored but not enforced at runtime. `POST /v2/hc-tools/{id}/test-run/public` to run the whole chain, or `POST /v2/api-function-configs/test-run/public` to test one HTTP call. ## Endpoint map Each `hc-tools` route is documented twice, once per type, since the same endpoint serves both. | Method | Path | Scope | Reference | | -------- | ------------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------- | | `GET` | `/v2/hc-tools/public` | `read` | [List actions](/en/api-reference/list-actions) · [List attributes](/en/api-reference/list-attributes) | | `GET` | `/v2/hc-tools/:id/public` | `read` | [Get action](/en/api-reference/get-action) · [Get attribute](/en/api-reference/get-attribute) | | `POST` | `/v2/hc-tools/public` | `write` | [Create action](/en/api-reference/create-action) · [Create attribute](/en/api-reference/create-attribute) | | `PATCH` | `/v2/hc-tools/:id/public` | `write` | [Update action](/en/api-reference/update-action) · [Update attribute](/en/api-reference/update-attribute) | | `DELETE` | `/v2/hc-tools/:id/public` | `write` | [Delete action](/en/api-reference/delete-action) · [Delete attribute](/en/api-reference/delete-attribute) | | `POST` | `/v2/hc-tools/:id/test-run/public` | `write` | [Test action](/en/api-reference/test-action) · [Test attribute](/en/api-reference/test-attribute) | | `GET` | `/v2/hc-tools/:id/junctions/public` | `read` | [Action assignments](/en/api-reference/list-action-agents) · [Attribute assignments](/en/api-reference/list-attribute-agents) | | `POST` | `/v2/hc-tools/junctions/public` | `write` | [Assign actions](/en/api-reference/assign-action-agents) · [Assign attributes](/en/api-reference/assign-attribute-agents) | | `GET` | `/v2/api-function-configs/public` | `read` | [List external API calls](/en/api-reference/list-data-steps) | | `GET` | `/v2/api-function-configs/:id/public` | `read` | [Get external API call](/en/api-reference/get-data-step) | | `POST` | `/v2/api-function-configs/public` | `write` | [Create external API call](/en/api-reference/create-data-step) | | `PATCH` | `/v2/api-function-configs/:id/public` | `write` | [Update external API call](/en/api-reference/update-data-step) | | `DELETE` | `/v2/api-function-configs/:id/public` | `write` | [Delete external API call](/en/api-reference/delete-data-step) | | `POST` | `/v2/api-function-configs/test-run/public` | `write` | [Test external API call](/en/api-reference/test-data-step) | ## Action or Attribute object Action or attribute ID. ISO 8601 creation timestamp. Workspace ID that owns the record. Display name. Human-readable description. Read by your team, not used for routing. `false` for an Action (rule-invoked), `true` for an Attribute (fetched automatically each conversation). Optional source. Current values include `ui`, `api`, `widget`, and integration providers such as `zendesk` and `intercom`. Typed inputs the action or attribute expects. Set through the update route. Typed outputs the action or attribute returns. Set through the update route. Set when the record is backed by a built-in integration handler instead of Data Steps. Read-only through the public API. ## InputSchemaField object Field name. Current values are `string`, `number`, `boolean`, `array`, `object`, and `date`. Whether the field is required. Optional runtime path to bind the value from. Optional literal value. Optional field source. Current values are `metadata`, `jwt`, and `apiResponse`. Optional default value. Optional path to auto-bind from runtime context. ## OutputSchemaField object Output field name. Current values are `string`, `number`, `boolean`, `array`, `object`, and `date`. Path to bind the output value from. For an API response field, use `[stepId].[responseMappingKey]`, where `stepId` is the external API call ID and `responseMappingKey` is a key from that step's `responseMapping`. The "Visible to AI" flag. When `true`, the resolved value is exposed to the agent. Applies to attributes. Optional field source. Current values are `metadata`, `jwt`, and `apiResponse`. When `source` is `apiResponse`, include the external API call ID in `path`. For example, if step `5fea0043-d7ae-45ea-951b-e007f4443e81` saves a response field as `hasBeenProcessed`, the matching output schema path is `5fea0043-d7ae-45ea-951b-e007f4443e81.hasBeenProcessed`. A bare `hasBeenProcessed` key can resolve at runtime, but the dashboard action editor will not show it as mapped in **Connect values to the fields that will be returned**. ## Data Step object Returned by the Data Step routes. Sensitive header and body values are masked on read (see below). Data Step ID. ISO 8601 creation timestamp. Workspace ID that owns the Data Step. Step name. ID of the action or attribute this step belongs to. Position of the step in the chain. Steps run in ascending order. Request URL. Supports `${fieldName}` interpolation from inputs and `${stepId.responseMappingKey}` interpolation from earlier external API calls. `{{placeholder}}` syntax is not supported. HTTP verb, for example `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. Request headers. Values are wrapped for masking (see below). Request body. Values are wrapped for masking (see below). Map of output keys to paths in the HTTP response (the "Save From Response" mapping). ## ResponseMapping object A map of output key to either a response path string, or an object with a path and data type. A path of `"."` means the entire response body. ```json theme={null} { "balance": "data.available_balance", "currency": { "path": "data.currency", "dataType": "string" } } ``` ## Sensitive values and masking Header and body values can be marked sensitive (for example, an API key). On read, a sensitive value comes back as `{ "hide": true, "value": "********" }`. Non-sensitive values come back as `{ "hide": false, "value": }`. When you update a Data Step, you can send the masked `"********"` back unchanged and the stored secret is preserved. Send a new string to replace it. To store a value as sensitive, send `{ "hide": true, "value": "" }`. ## Action or Attribute test-run result Returned by [Test action](/en/api-reference/test-action) and [Test attribute](/en/api-reference/test-attribute). Name of the action or attribute that ran. Action or attribute ID. Action or attribute name. Whether every Data Step in the chain succeeded. Final output values, keyed by output field name. For attributes, a map of output field name to its `sendToLlm` (Visible to AI) flag. Empty for actions. Per-step results, including the resolved request and each step's extracted data. ## Data Step test-run result Returned by [Test data step](/en/api-reference/test-data-step). Whether the HTTP call succeeded. HTTP status code of the outbound call. Raw response body from the call. Present when the call failed. ## Agent assignment object Returned by the [action](/en/api-reference/list-action-agents) and [attribute](/en/api-reference/list-attribute-agents) agent-assignment routes. Assignment ID. Agent ID the action or attribute is assigned to. Action or attribute ID. Workspace ID. Channels the assignment applies to, for example `chat` and `email`. # Overview Source: https://docs.usefini.com/en/api-reference/agents Create, list, and delete workspace agents through Fini's public API. Agents are the workspace entities that answer conversations, use prompts, run rules, and connect to knowledge. The public API still uses `/bots` in the wire-format paths because that is the current backend contract. Use this family when you need to create an agent, discover `botId` values for other API calls, or delete an agent. In the dashboard and most docs, these entities are called **agents**. In public API paths and some response fields, the same entity appears as **bot**. ## Reference pages `POST /v2/bots/public` - create a workspace agent by name. `GET /v2/bots/public` - list workspace agents and their serialized prompt text. `DELETE /v2/bots/{id}/public` - delete one agent by ID. Read prompt configuration, inspect saved versions, and save new prompt versions for an agent. Fetch performance summaries, chart datasets, knowledge usage, rule analytics, and escalation breakdowns. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | --------------------- | ------- | ----------------------------------------- | | `POST` | `/v2/bots/public` | `write` | Create a new agent in the workspace. | | `GET` | `/v2/bots/public` | `read` | List non-deleted agents in the workspace. | | `DELETE` | `/v2/bots/:id/public` | `write` | Delete one agent. | ## Related endpoint families | Family | Routes | When to use | | ----------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | [Prompts](/en/api-reference/prompts) | `/v2/bots/:id/hc-prompt/.../public` | Read and save the instruction layers for one agent. | | [Analytics](/en/api-reference/analytics) | `/v2/bots/:id/hc-analytics/.../public` | Export summary metrics, charts, knowledge usage, rule analytics, and escalation breakdowns. | | [Conversations](/en/api-reference/list-conversations) | `/v2/hc-interactions/.../public` | Export conversations, send a new turn, approve a response, or run Refine with AI review. | | [Knowledge](/en/api-reference/knowledge) | `/v2/knowledge/public`, `/v2/hc-articles/.../public`, `/v2/hc-folders/.../public` | Generate, manage, organize, and assign knowledge used by agents. | | [Rules](/en/api-reference/rules) | `/v2/hc-rules/.../public` | Create, publish, restore, or delete Intent Rules and Business Rules assigned to agents. | # Overview Source: https://docs.usefini.com/en/api-reference/analytics Fetch performance summaries, chart datasets, knowledge usage, rules performance, and escalation breakdowns for one agent. Analytics endpoints return reporting data for one agent over a requested time window. Use them to export the same core metrics the dashboard uses: conversation volume, resolution rate, response time, knowledge usage, rule performance, escalation reasons, hourly volume, and CSAT data when available. The API paths are scoped by agent ID because analytics are calculated for one workspace agent at a time. Use [List agents](/en/api-reference/list-agents) to find the `botId` to pass as `{id}`. In the dashboard and most docs, these entities are called **agents**. In public API paths and some response fields, the same entity appears as **bot**. ## Reference pages `GET /v2/bots/{id}/hc-analytics/public` - return the full analytics summary for one agent. `GET /v2/bots/{id}/hc-analytics/{section}/public` - return one analytics section. ## Endpoint map | Method | Path | Scope | Purpose | | ------ | ------------------------------------------- | ------ | ------------------------------------------- | | `GET` | `/v2/bots/:id/hc-analytics/public` | `read` | Fetch all analytics sections for one agent. | | `GET` | `/v2/bots/:id/hc-analytics/:section/public` | `read` | Fetch one analytics section for one agent. | ## Query model Both endpoints use the same filter model: | Query | Required | Purpose | | ------------------------ | -------- | ------------------------------------------------------------------------ | | `startEpoch` | Yes | Start of the analytics window as a Unix epoch timestamp. | | `endEpoch` | Yes | End of the analytics window as a Unix epoch timestamp. | | `source` | No | Conversation source filter. Pass `all` to include all supported sources. | | `channel` | No | Channel filter. | | `latestStatus` | No | Latest conversation status filter. | | `latestSentiment` | No | Latest sentiment filter. | | `usedSubfolderIds` | No | Knowledge subfolder filter. | | `tagIds` | No | Tag filter. | | `ruleIds` | No | Rule filter. | | `escalationReasonTagIds` | No | Escalation-reason tag filter. | | `csatRatings` | No | CSAT rating filter. Values must be integers from `1` through `5`. | | `timezone` | No | Timezone used for date grouping. | Use [Get agent analytics](/en/api-reference/get-agent-analytics) when you need the complete payload. Use [Get agent analytics section](/en/api-reference/get-agent-analytics-section) when you only need `summary`, `trends`, `knowledge`, `rules`, or `escalations`. # Assign to agents Source: https://docs.usefini.com/en/api-reference/assign-action-agents POST https://api-prod.usefini.com/v2/hc-tools/junctions/public Add or remove agent assignments for actions. Adds or removes assignments between agents and actions. Send a batch of junction changes in one request. Assigning an action to an agent does not make it run. An action executes only when a published [Rulebook](/en/automations/rulebook) rule, assigned to that agent, invokes it through a Tool node. The backend stores action assignments but does not currently check them at runtime; assignments gate [Attributes](/en/api-reference/attributes) only. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Array of junction changes to apply. Agent ID. Action ID. `ADD` to create the assignment, `DELETE` to remove it. Optional channels the assignment applies to, for example `chat` and `email`. ## Response Returns `{ "success": true }` when the changes are applied. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/junctions/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "junctions": [ { "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "action": "ADD", "channels": [ "chat" ] } ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/junctions/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'junctions': [ { 'botId': '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', 'toolId': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', 'action': 'ADD', 'channels': [ 'chat' ] } ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/junctions/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "junctions": [ { "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "action": "ADD", "channels": [ "chat" ] } ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "actionIds": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "attached": true } ``` ## Errors The body is malformed, or a junction is missing `botId`, `toolId`, or a valid `action`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Assign to agents Source: https://docs.usefini.com/en/api-reference/assign-attribute-agents POST https://api-prod.usefini.com/v2/hc-tools/junctions/public Add or remove agent assignments for attributes. Adds or removes assignments between agents and attributes. Send a batch of junction changes in one request. An attribute only runs in conversations for agents it is assigned to. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Array of junction changes to apply. Agent ID. Attribute ID. `ADD` to create the assignment, `DELETE` to remove it. Optional channels the assignment applies to, for example `chat` and `email`. ## Response Returns `{ "success": true }` when the changes are applied. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/junctions/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "junctions": [ { "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "action": "ADD", "channels": [ "chat" ] } ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/junctions/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'junctions': [ { 'botId': '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', 'toolId': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', 'action': 'ADD', 'channels': [ 'chat' ] } ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/junctions/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "junctions": [ { "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "action": "ADD", "channels": [ "chat" ] } ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "attributeIds": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "attached": true } ``` ## Errors The body is malformed, or a junction is missing `botId`, `toolId`, or a valid `action`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Overview Source: https://docs.usefini.com/en/api-reference/attributes Fetch the customer context your AI agent needs (plan, order, account state) before every reply, so answers are personalized rather than generic. An agent that doesn't know *who* it's talking to gives generic answers. **User Attributes** is how Fini fetches the customer's context, fresh on every message, so the agent can reference the customer's actual plan, order, account state, or any other detail you'd otherwise have to look up by hand. User Attributes page in the Fini Demo workspace showing the selected agent, two configured attributes, field counts, availability toggles, and the New Attribute button In the dashboard, this page lives under **API Setup → Attributes**. The list is scoped by the agent selector in the sidebar: with a specific agent selected, the page shows which attributes are available to that agent and whether each one is toggled on. ## The model An attribute is three decisions: ```mermaid theme={null} --- title: How an attribute works --- flowchart LR SRC["1 · SOURCE
native context
to start from"] --> FLD["2 · FIELDS
native + external,
what you get back"] FLD --> SW["3 · SWITCHES
who downstream
can see each field"] SW --> LLM["The agent"] SW --> RB["Rulebook"] SW --> APIN["Later API steps"] ``` 1. **Source**: the native conversation context the attribute starts from. You pick one when you create the attribute: your app's UI metadata, a signed widget JWT, or a connected integration. The source seeds the attribute with fields and (for integrations) credentials. 2. **Fields**: what you end up with. Fields arrive from four groups in the **Available Data** panel: System Attributes, passed-in UI/JWT fields, connected-integration metadata, and fields collected by **external API calls**. The first three are native (no HTTP call you write); the fourth is an API chain that can reach any endpoint, your internal API, Shopify, anything, independent of the source. 3. **Switches**: each field has up to three independent switches that decide *who downstream can use it*. Toggling a switch doesn't move data; it exposes the field to that consumer. At runtime, Fini fetches every attribute attached to the responding agent before each LLM call and exposes the resulting fields as conversation context. The rest of this page walks each decision in order, then shows the pattern applied end-to-end. For a walkthrough showing how User Attributes feeds into Actions, Rulebook, and Reply Behavior end-to-end, see [End-to-end: cancellation flow](/en/walkthroughs/cancellation-flow). ## 1 · Source: where data comes from Each attribute has a **source**, picked when you create it. The source seeds the attribute with a starting set of fields and (for integrations) credentials: | Source | What it seeds the attribute with | Typical use | | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **App UI** (`ui`) | Metadata your app passes when it embeds Fini. | Logged-in user's id / plan / role from your dashboard. | | **Widget** (`widget`) | The signed JWT payload your backend hands the widget. | Authenticated widget conversations (you sign a JWT with the [Widget Signing Key](/en/deploy/widget#signing-key) and pass user fields inside it). | | **Connected integration** (Zendesk, Intercom, Front, Gorgias, HubSpot, Salesforce, LiveChat) | The integration's standard conversation objects, plus its API credentials. | Look up the customer in Zendesk by email, read the ticket's status, etc. | The source is only the starting point, it seeds native context. Anything the source doesn't already provide is fetched via [external API calls](#attributes-from-external-systems), available to every attribute regardless of source. Sources are gated by what's connected: integrations show up in the dropdown only if you've connected them on the corresponding [Deploy page](/en/deploy/overview) (helpcenter is excluded), and `widget` only shows up if you have at least one widget created. ## 2 · Fields: what you can fetch Fields arrive from **four groups**, all in the **Available Data** panel, which describes itself: *"Data your AI can reference. For each field, choose independently whether it's used as an API input, available in the Rulebook, and shared with the LLM."* Each group shows an enabled-over-total count in its header (e.g., *System Attributes 7/8*, *Conversation 2/11*, *Collected attributes 44/44*) so you can see at a glance how many are switched on. | Group | Available for | Where it comes from | | ------------------------ | ------------------------------------------------------------------- | -------------------------------------------------------------------------- | | **System Attributes** | Every attribute | The conversation itself (always present) | | **Passed-in fields** | UI / Widget sources | Your embed metadata or signed JWT | | **Integration metadata** | Any source (credentials); integration sources (conversation fields) | A connected native integration | | **External systems** | Any source | An API chain you configure, see [below](#attributes-from-external-systems) | The first three are **native**: the data is already in Fini because of how the agent is reached, so there's no HTTP call you write. The fourth is **external**: an API chain that fetches anything the source doesn't already provide. Each group is detailed below. ### System Attributes (always available) Every attribute, regardless of source, exposes the same set of universal **System Attributes** about the conversation itself: The customer's display name, when known. The customer's email, when known. Whether this conversation arrived on an email channel or a chat channel. True if the inbound message has any attachments. Time of the inbound message in UTC. Day of the week of the inbound message in UTC. True if the inbound message landed Mon-Fri UTC. Useful for "stay silent off-hours" rules. The integration the conversation came from, `zendesk`, `intercom`, `widget`, `ui`, and so on. Use these for time- or channel-based rules without needing any external lookup. They're free to enable; no API call runs. ### Passed-in fields (UI / Widget sources only) For the **App UI** source, fields you've passed in via your embed metadata. For the **Widget** source, fields inside the JWT payload your backend signed. * These are **automatically visible to the AI** by default, even if you don't list them here. * Listing them here gives you two extra abilities: * Reference them in [Rulebook](/en/automations/rulebook) and [Reply Behavior](/en/automations/reply-behavior) conditions. * Use them as inputs to API steps further down (for example, pass a user id from the JWT into a Zendesk API call). ### Integration metadata fields This section covers two distinct things that share a UI panel: **connected-integration credentials** (always available) and **conversation-level fields** (only for integration-source attributes). **Connection Settings (credentials, cross-source).** Every connected integration exposes its **Connection Settings** group regardless of which source you picked for this attribute. So a widget-source or UI-source attribute can pull Zendesk's subdomain and access token to call Zendesk's API directly, without rebuilding auth on your side. The group label in the editor is ` Settings` (e.g., "Zendesk Settings"). Toggle **Use as Input in API** on the credential fields, then insert them by their display name into your Data Collection Steps via the `$` picker. If you have multiple integrations connected, each one's Connection Settings appears as its own group. **Conversation-level fields (integration sources only).** For an integration source, the same panel also shows fields directly available on the integration's standard objects (e.g., a Zendesk ticket's status, a Salesforce case's priority). No API call needed; Fini reads them as part of the conversation context the integration already provides. Use these when the field is on the conversation object itself ("the customer's email is on the ticket"); they're cheaper and more reliable than a custom API step. The full field catalog for every integration is in the [integration field catalog](#reference-integration-field-catalog) at the end of this page. The same list is visible live in the editor when you create an attribute. ### Attributes from External Systems The fourth field group, and the only one that costs an HTTP call you write. The distinction that matters: * **Native integrations** (Zendesk, HubSpot, Salesforce, and the others) are connected once on the Deploy page. Fini knows their object shape, so they come with a **pre-built field catalog** you just toggle on. * **External systems** are *any other HTTP endpoint*, your own internal API, Shopify, a data warehouse, or even a native integration's REST API. There's **no catalog**: you supply the URL, headers, and auth, and declare which response fields to keep. For Redshift, Snowflake, BigQuery, Postgres, and similar systems, expose a scoped HTTPS endpoint in front of the warehouse. See [Database and Warehouse Connections](/en/api-reference/database-warehouses). A **multi-step chain of HTTP requests**, available to every attribute regardless of source. Each step is one HTTP call; later steps can use any field collected by earlier steps as input. The UI labels this section **Attributes from External Systems**, with the helper text *"Make API calls to fetch additional data. Any field from above, as well as collected attributes from a given API step, can be used as input in subsequent steps."* Steps are configured under **Data Collection Steps** (*"Configure the sequence of API calls that collect the attributes shown above"*). Each step has: * A **Step Name** and **Method** (GET / POST / PUT / PATCH / DELETE), plus the **URL**. Type `$` in any field to insert a dynamic value. * A **Headers** block and request body, as JSON. Use the `$` picker to interpolate any field from the sections above whose **Use as Input in API** switch is on, for example, the user's email in the URL, or an API key in an `x-api-key` header. * A **Save From Response** block: the fields to pull out of the response, in `"mappedName": "json_path"` form. The fields you map populate the **Collected attributes** table, where each row shows only **Use in Rulebooks** and **Visible to AI** (no input switch) and is labelled with the step that produced it. ## 3 · Switches: who can see each field Most fields show three independent switches in the editor table. They don't move data, they expose a field to a downstream consumer: * **Use as Input in API**: makes the field available to your Data Collection Steps as a dynamic value you can insert into URLs, headers, or request bodies. In any step field, type `$` to open the picker; Fini inserts the field by its **display name**. Turn this on for credentials and identifiers you want to inject into HTTP calls. * **Use in Rulebooks**: exposes the field as a condition input in [Rulebook](/en/automations/rulebook) and [Reply Behavior](/en/automations/reply-behavior). Off by default; flip on for fields you want to write rules against. * **Visible to AI**: includes the field in the LLM's context for that conversation. Off by default; flip on for fields the agent should reference when answering. The switches are independent. The patterns that recur: | Field kind | Input in API | Rulebooks | Visible to AI | | -------------------------------------- | ------------ | --------- | ------------- | | A credential (bearer token, subdomain) | ✓ | | | | A customer plan / tier | | ✓ | ✓ | | An order / ticket id | ✓ | ✓ | ✓ | **Don't make every field visible to AI.** The LLM context window has a budget; fields that aren't useful for answering questions just dilute the signal. Default to off, flip on the handful of fields that genuinely help the agent personalize its reply. Fields collected from API responses (the **Collected attributes** table under Data Collection Steps) only show **Use in Rulebooks** and **Visible to AI**: they're automatically available to subsequent API steps in the same chain by name, so no input switch is needed. ## Creating a user attribute Land on **API Setup → Attributes** in the sidebar. The list shows every attribute you've created so far, scoped to the agent you have selected in the sidebar. * **Name** (required): how this attribute shows up in the list and in test logs (e.g., "Customer Plan", "Recent Orders"). * **Description** (optional): a sentence about what this attribute fetches. Useful when teammates open the page later. * **Source** (required): pick from the dropdown. Determines which field-source sections you'll see in the detail view. Create New Tool for User Attributes dialog showing Name, Description, Source, Cancel, and Create controls The detail view opens. Walk through each section: System Attributes, your source's passed-in or integration-metadata fields, and (if needed) Data Collection Steps for the API chain. Attribute detail view for a UI source showing the System Attributes, UI Metadata Attributes, Attributes from External Systems, and Data Collection Steps sections For each field, decide independently whether it's **Use as Input in API**, **Use in Rulebooks**, **Visible to AI**, or some combination. Credentials are typically input-only; identifiers like an order id are often all three; sentiment fields are usually rule + AI but not input. Click the **Play** button at the top of the detail view. The Test panel opens; provide sample inputs and run the chain step by step to confirm fields come back as expected before the agent relies on them. Each Data Collection Step also has its own play button for testing in isolation. Click **Save**. Subsequent chat messages will fetch this attribute as part of building the agent's context. ## Deploying attributes for an AI agent The sidebar has an **agent dropdown**. With **Company level** selected, the list shows workspace-level configuration. Picking a specific agent scopes the list to that agent: each attribute row shows whether it is available to the selected agent, plus its field count. Attributes page in agent-scoped mode showing attribute cards with availability controls, field counts, and selected-agent status * The **Always-Get** banner at the top of the list is a reminder: every attached attribute runs on every chat message for the selected agent. There's no "fetch on demand" mode; if it's attached, it runs. * Each attribute card shows the **Chat** and **Email** channel tags it's currently active on, plus an "Active for \[agent name] on Chat & Email"-style status line. Use the checkbox on the card to toggle attachment. * The card also shows the total **field count** the attribute exposes (system + passed-in + collected). * Click **Save** in the top-right to commit attachment / channel changes; **Cancel** discards. If an agent has no attributes attached, no per-message lookup runs for it. Conversations on that agent get only the defaults the integration already provides (sender email, conversation subject, etc.) plus the System Attributes. Deleting an attribute also deletes the API steps configured under it. The action is **irreversible**; the confirmation dialog calls this out. If the attribute is attached to agents, the attachment is removed from those agents automatically. ## When attributes run User attributes attached to the responding agent are **fetched on every chat message** before the agent composes its reply. The chain runs server-side; the customer doesn't see anything happen. Because they're fetched up front, the resulting fields are available to the LLM, [Rulebook](/en/automations/rulebook), and [Reply Behavior](/en/automations/reply-behavior) (under the `User Attributes` field group), each according to the per-field switches described in [Switches](#3--switches-who-can-see-each-field). The fetch is per-message, so if a customer's plan changes mid-conversation, the next message picks up the new value. ## Worked examples Every attribute follows the same shape: **create → expose source fields → call an API → toggle collected fields → attach to an agent.** The three examples below apply that shape to the three sources. Pick the tab that matches how your agent is deployed, you only need the one. **Order status from UI metadata.** Your app embeds the Fini agent and passes a per-conversation order id plus an auth token via UI metadata. Fini calls your order API with those, gets back the order's status, and exposes it to the agent. Attribute detail view for a UI source where Token and Order Id UI Metadata Attributes feed a Get Order Status API step that collects orderStatus **Name:** *Get Attributes for Fini UI Inbox Conversation*. **Source:** `ui`. Two passed-in fields, both with all three switches on: | Field | Use as Input in API | Use in Rulebooks | Visible to AI | | -------- | ------------------- | ---------------- | ------------- | | Token | ✓ | ✓ | ✓ | | Order Id | ✓ | ✓ | ✓ | **Use as Input in API** lets the API step interpolate them; **Visible to AI** lets the LLM see the order id; **Use in Rulebooks** lets a rule match on them later. **Name:** *Get Order Status*. **Method:** `GET`. Configure: ```http theme={null} URL: https://api.yourstore.com/orders/${Order Id} Headers: {"Authorization": "${Token}"} Save From Response: {"orderStatus": "order.status"} ``` The `${Order Id}` and `${Token}` tokens are the passed-in fields by their display name, inserted with the `$` picker. The `order.status` path on the right of Save From Response is the JSON path inside your API's response. The chain produces one collected field, `orderStatus`. Toggle **Visible to AI** so the agent can reference it in its reply ("Your order is in transit and will arrive Monday"). To suppress the agent off-hours, toggle **Use in Rulebooks** + **Visible to AI** on `Is Weekday (UTC)` so a [Reply Behavior](/en/automations/reply-behavior) rule can stay silent when it's false. Pick the agent from the top-right dropdown, toggle the attribute on, leave Chat + Email tags as-is (or trim to one channel if needed), and click **Save**. **Business hours from Zendesk via the widget.** A widget-source attribute uses the customer's `accountType` from the signed JWT, then calls Zendesk's API, using credentials made available by the connected Zendesk integration, to get the team's business hours schedules. The agent can then answer "are we open?" without you wiring anything custom. Attribute detail view for a Widget source showing System Attributes, Zendesk Settings, JWT Token Attributes, External Systems, and Data Collection Steps **Name:** *Get Attributes for Fini Widget Conversation*. **Source:** `widget`. Pick the universal fields useful for this agent. A common set turns on **Use in Rulebooks + Visible to AI** for User Name, User Email, Has Attachment, and Time (UTC). Because Zendesk is connected on the Deploy page, its **Zendesk Settings** group appears here even though the attribute source is `widget`. Toggle **Use as Input in API** on: | Field | Use as Input in API | | ------------------------- | ------------------- | | Zendesk Account Subdomain | ✓ | | Zendesk API Access Token | ✓ | Leave Use in Rulebooks / Visible to AI off, credentials shouldn't be exposed to the LLM. Your backend signs a JWT containing an `accountType` claim and hands it to the widget. List `accountType` under **JWT Token Attributes** with **Use in Rulebooks + Visible to AI** so a Rulebook condition can match on it and the agent knows the tier. **Name:** *Get Business Hours Schedules from Zendesk*. **Method:** `GET`. Configure: ```http theme={null} URL: https://${Zendesk Account Subdomain}.zendesk.com/api/v2/business_hours/schedules.json Headers: {"Authorization": "Bearer ${Zendesk API Access Token}"} Save From Response: {"schedules": "schedules"} ``` The `${Zendesk Account Subdomain}` and `${Zendesk API Access Token}` tokens are the Zendesk Connection Settings fields by their exact catalog label, inserted via the `$` picker. The right side of Save From Response is the JSON path in Zendesk's response, Zendesk returns `{ schedules: [...] }`, so the path is `schedules`. The chain produces `schedules` (array). Toggle **Use in Rulebooks + Visible to AI** so the agent can reason about whether the conversation arrived during business hours. This pattern (widget source + cross-source credentials + integration API call) generalizes to any "widget needs data from your helpdesk" case: ticket lookup by JWT user id, last conversation summary, organization details, and so on. **Enriching Zendesk tickets.** When the agent replies on Zendesk tickets, you usually want more than the raw ticket subject. A Zendesk-source attribute exposes Zendesk's standard Ticket fields directly, plus the connection's credentials so you can call any Zendesk API for richer context. New Attribute dialog with Source set to zendesk **Name:** *Get Attributes for Zendesk Tickets*. **Source:** `zendesk`. Under the **Ticket** field group, toggle **Visible to AI** on the fields the agent should reference when answering. A common minimum: | Field | Use in Rulebooks | Visible to AI | | --------------- | ---------------- | ------------- | | Status | ✓ | ✓ | | Priority | ✓ | ✓ | | Subject | | ✓ | | Type | ✓ | | | Group Id | ✓ | | | Organization Id | ✓ | | Status and Priority are usually both rule + AI inputs (for triage rules and for the agent to acknowledge urgency). Group Id and Organization Id are typically rule-only, you don't want the LLM mentioning internal ids. The full set of Ticket fields is in the [integration field catalog](#reference-integration-field-catalog). Under **Zendesk Settings**, toggle **Use as Input in API** on: | Field | Use as Input in API | | ------------------------- | ------------------- | | Zendesk Account Subdomain | ✓ | | Zendesk API Access Token | ✓ | Leave Use in Rulebooks / Visible to AI off; credentials shouldn't be exposed to rules or the LLM. With these toggled, your Data Collection Steps can insert the Zendesk subdomain and access token by their display names via the `$` picker. A common second step fetches the ticket's requester profile so the agent knows who's asking. **Name:** *Get Requester*. **Method:** `GET`. Configure: ```http theme={null} URL: https://${Zendesk Account Subdomain}.zendesk.com/api/v2/users/${Requester Id}.json Headers: {"Authorization": "Bearer ${Zendesk API Access Token}"} Save From Response: { "requesterRole": "user.role", "requesterTags": "user.tags", "requesterOrg": "user.organization_id" } ``` `${Requester Id}` is the Ticket field by its catalog label, available because it's in the Available Data section with **Use as Input in API** on. `requesterRole`, `requesterTags`, `requesterOrg`: pick **Use in Rulebooks + Visible to AI** for VIP-detection rules and richer responses. Tags is usually the most useful, a customer tagged `vip` or `enterprise` is exactly the conversation you want to handle differently. Pick the agent from the top-right dropdown, toggle the attribute on, leave Email selected (chat tickets in Zendesk are a separate channel; enable both or split into two attributes). Save. The same pattern works for **Intercom**, **Front**, **HubSpot**, **Gorgias**, **Salesforce**, and **LiveChat**: pick conversation-level fields from Available Data, toggle the integration's credentials for API inputs, then enrich with API steps as needed. The per-integration field catalog is in the [integration field catalog](#reference-integration-field-catalog). ## Why a field isn't reaching the agent Open the page with that agent selected, confirm the attribute toggle is on, and Save. This is the most common cause. Even if the chain runs and collects the value, the LLM doesn't see it until the switch is on. The value can still be present for Rulebooks while invisible to the agent. Run the **Test** panel with realistic inputs. A step returning 404 (customer not found) or 401 (token expired) leaves every downstream field blank. Re-authorize on the [Deploy page](/en/deploy/overview) for that integration. The attribute can't fetch from a disconnected source. Check the channel selection on the agent-attribute row. A Chat-only attribute won't run on an email conversation. ## Reference: integration field catalog The fields each connected integration exposes. **Connection Settings** are credentials available from any source; the object groups (Ticket, Conversation, Case, etc.) are conversation-level fields available only when the attribute's source is that integration. This same list appears live in the editor. **Connection Settings**: credentials, useful as API-step headers and URLs. Your Zendesk subdomain (the part before `.zendesk.com`). Used to construct API URLs. Bearer token for Zendesk API calls. Toggle Use as Input in API only; never expose to Rulebooks or the LLM. **Ticket**: fields directly on the current Zendesk ticket. The ticket's unique identifier. The ticket's URL in your Zendesk instance. The ticket's title. The full description text of the ticket. The ticket's subject line. The id of the assigned agent. Custom status id if your Zendesk uses custom statuses. External system id, if your tickets are synced from another source. True if the ticket originated from a messaging channel (vs. email). The Zendesk group the ticket is assigned to. Typically rule-only. True if this ticket has child incident tickets. The customer's organization id in Zendesk. Useful for B2B routing. Ticket priority: `low`, `normal`, `high`, or `urgent`. The id of the customer who submitted the ticket. Used as input to fetch the requester's profile. Ticket status: `new`, `open`, `pending`, `hold`, `solved`, `closed`. The id of whoever submitted the ticket (may differ from the requester). Ticket type: `problem`, `incident`, `question`, `task`. The Zendesk brand the ticket is on. **Connection Settings** Bearer token for Intercom API calls. Toggle Use as Input in API only. **Conversation**: fields on the current Intercom conversation. The conversation's unique identifier. The conversation type. The conversation's title. True if the conversation is open. The conversation's state. True if the conversation has been read. The conversation's priority level. The id of the assigned admin. The id of the assigned team. Tags attached to the conversation. Contacts (customers) on the conversation. **Connection Settings** Bearer token for HubSpot API calls. Toggle Use as Input in API only. **Thread**: the HubSpot conversation thread. The thread's unique identifier. Thread status. The id of the channel the thread originated on. The account id within that channel. The agent assigned to the thread. True if the thread is marked as spam. True if the thread is archived. The inbox the thread lives in. The HubSpot contact id linked to the thread. The HubSpot ticket id, if the thread is associated with one. **Contact**: the customer record. The contact's unique identifier. ISO timestamp when the contact was created. ISO timestamp of the last update. True if the contact is archived. Full properties bag of the HubSpot contact record. **Channel Details** Channel identifier. Channel name. **Ticket** HubSpot ticket id. True if the ticket is archived. **Connection Settings** Your Salesforce subdomain. Bearer token for Salesforce API calls. Toggle Use as Input in API only. **Case**: the current Salesforce case. The case's unique identifier. Master record id (if merged from another case). Human-readable case number. The customer contact's id. The customer account's id. Asset id associated with the case, if any. Source id of the case. Parent case id, if this is a child case. Phone number the customer supplied. Company name the customer supplied. Case type. Case status. Case reason (e.g., installation, performance, complaint). How the case originated (web, phone, email, etc.). Case subject line. Case priority. Full case description. True if the case is closed. ISO date the case was closed. True if the case has been escalated. Case owner's id. Id of whoever created the case. **Connection Settings** Bearer token for Front API calls. Toggle Use as Input in API only. **Conversation** The conversation's unique identifier. Conversation subject line. Conversation status. True if the conversation is private. **Connection Settings** Your Gorgias subdomain. Bearer token for Gorgias API calls. Toggle Use as Input in API only. **Ticket** The ticket's unique identifier. The ticket's URL in your Gorgias instance. Channel the ticket arrived on. External system id. True if the latest message was from an agent (not the customer). How the ticket was created. Ticket status. The team the ticket is assigned to. Detected language of the ticket. Ticket subject. **Connection Settings** Bot bearer token for LiveChat API calls. Toggle Use as Input in API only. LiveChat exposes only Connection Settings as integration metadata today. To pull conversation- or customer-level fields, use a Data Collection Step, see [Attributes from External Systems](#attributes-from-external-systems). # Overview Source: https://docs.usefini.com/en/api-reference/business-rules Create and manage widget-escalation Business Rules through the public API. Business Rules are the workflows configured under [Automations → Business Rules](/en/automations/business-rules). Send `type: "business"` when creating them and `type=business` when listing them. Business Rules are not versioned. They are stored and updated directly, and currently run for `source: "widget"` with `triggerType: "on_escalation"`. ## Business-rule endpoints ### Endpoints shared with intent rules | Method | Path | Scope | Business-rule usage | | -------- | ------------------------------------ | ------- | ------------------------------------------------------------------------ | | `GET` | `/v2/hc-rules/public` | `read` | List with `type=business` and optional `source=widget`. | | `GET` | `/v2/hc-rules/fields-context/public` | `read` | Get fields with `type=business`, including Business Rule context fields. | | `GET` | `/v2/hc-rules/:id/public` | `read` | Get one Business Rule with its full tree. | | `POST` | `/v2/hc-rules/public` | `write` | Create a custom or template-based Business Rule. | | `PATCH` | `/v2/hc-rules/:id/public` | `write` | Update the stored rule directly. | | `DELETE` | `/v2/hc-rules/:id/public` | `write` | Delete the rule and its agent assignments. | ### Business-only endpoint | Method | Path | Scope | Purpose | | ------ | ----------------------------- | ------ | ------------------------------------------- | | `GET` | `/v2/hc-rules/default/public` | `read` | List Fini-provided Business Rule templates. | ## Custom and template-based rules | Mode | Create request | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Custom | Send `type: "business"`, `source: "widget"`, `triggerType: "on_escalation"`, and a `flowConfig`. | | Template-based | Send `type: "business"` and a `defaultRuleId` from [List default rules](/en/api-reference/list-default-rules). Do not send `flowConfig`. Use `inputSchema` to bind template inputs. | Business Rules cannot be drafts. Do not send `status: "DRAFT"`, and do not call draft-generation, version, publish, or restore endpoints for them. ## Business-rule response fields Business Rules use the shared [`Rule`](/en/api-reference/rules#rule-object) shape. The relevant Business Rule fields are `type`, `source`, `triggerType`, `defaultRuleId`, `inputSchema`, `flowConfig`, and `botIds`. Intent-rule version fields do not apply. # Create action Source: https://docs.usefini.com/en/api-reference/create-action POST https://api-prod.usefini.com/v2/hc-tools/public Create a rule-invoked action. Creates an [`Action`](/en/api-reference/actions-and-attributes#action-or-attribute-object): an outbound API call invoked by a [Rulebook](/en/automations/rulebook) Tool node. Omit `alwaysGet` or send `false`; sending `true` creates an [Attribute](/en/api-reference/create-attribute) instead. This route creates the record only. Add the input and output schema with [Update action](/en/api-reference/update-action), then add its HTTP calls with [Create data step](/en/api-reference/create-data-step). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Display name. Optional human-readable description. Leave as `false` for an action. `true` creates an attribute that runs automatically each conversation. Optional source. Current values include `ui`, `api`, `widget`, and integration providers such as `zendesk` and `intercom`. ## Response Returns the created [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). `inputSchema` and `outputSchema` start empty. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": false, "source": "api" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'alwaysGet': false, 'source': 'api' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": False, "source": "api" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Cancel subscription", "description": "Cancel an active subscription in billing.", "inputFields": [ { "name": "customerId", "type": "string", "required": true } ], "outputFields": [ { "name": "confirmationId", "type": "string" }, { "name": "effectiveDate", "type": "string" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed or `source` uses an unsupported value. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while creating the record in storage. # Create agent Source: https://docs.usefini.com/en/api-reference/create-agent POST https://api-prod.usefini.com/v2/bots/public Create a new agent in the workspace. Creates a new agent in the workspace tied to your API key and returns the stored agent object. Agent names must be unique within the workspace. If another agent already has the same name, this route returns `400 Bad Request`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Name for the new agent. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/bots/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{"name":"Support Agent"}' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/bots/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={"name": "Support Agent"}, ) agent = response.json() ``` ```javascript Node.js theme={null} const response = await fetch("https://api-prod.usefini.com/v2/bots/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Support Agent" }), }); const agent = await response.json(); ``` ## Response Returns the created agent object. Agent ID. Pass this value as `botId` on endpoints that scope behavior to one agent. Agent name. Workspace company ID that owns the agent. ISO 8601 timestamp for when the agent was created. ISO 8601 timestamp for when the agent was last updated. Agent flow mode when present. Current values are `default` and `fast_answer`. ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Support Agent", "companyId": "5c9c6da2-0ed8-4f75-8b21-7c5fcb0bb14a", "createdAt": "2026-07-21T06:12:31.456Z", "updatedAt": "2026-07-21T06:12:31.456Z", "hcFlowMode": "default" } ``` ## Errors The body is malformed or another agent with the same name already exists in the workspace. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while creating the agent. # Create attribute Source: https://docs.usefini.com/en/api-reference/create-attribute POST https://api-prod.usefini.com/v2/hc-tools/public Create an always-on attribute. Creates an [`Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object): an outbound API call that runs automatically at the start of a conversation to load context (for example, a `GetUserInfo` lookup). Send `alwaysGet: true`; omitting it creates an [Action](/en/api-reference/create-action) instead. This route creates the record only. Add the input and output schema with [Update attribute](/en/api-reference/update-attribute), then add its HTTP calls with [Create data step](/en/api-reference/create-data-step). An attribute only runs for agents it is assigned to; see [Assign to agents](/en/api-reference/assign-attribute-agents). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Display name. Optional human-readable description. Send `true` to create an attribute. `false` (the default) creates a rule-invoked action instead. Optional source. Current values include `ui`, `api`, `widget`, and integration providers such as `zendesk` and `intercom`. ## Response Returns the created [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). `inputSchema` and `outputSchema` start empty. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": true, "source": "widget" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'alwaysGet': true, 'source': 'widget' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": True, "source": "widget" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Customer plan", "description": "Fetches the customer's active plan.", "source": "widget", "fields": [ { "name": "plan", "type": "string", "visibleToAi": true, "useInRulebooks": true } ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed or `source` uses an unsupported value. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while creating the record in storage. # Create external API call Source: https://docs.usefini.com/en/api-reference/create-data-step POST https://api-prod.usefini.com/v2/api-function-configs/public Create an external API call step for an action or attribute. Creates one external API call for an action or attribute. The wire-format object is still called [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object). Steps run in `stepNumber` order, each feeding its extracted output into the next. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Step name. Request URL. Supports `${fieldName}` interpolation from inputs and `${stepId.responseMappingKey}` interpolation from earlier external API calls. `{{placeholder}}` syntax is not supported. HTTP verb, for example `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. ID of the action or attribute this step belongs to. Set it so the step runs as part of that chain. Position of the step in the chain. Steps run in ascending order. Request headers. To store a value as sensitive, send `{ "hide": true, "value": "" }`. See [Sensitive values and masking](/en/api-reference/actions-and-attributes#sensitive-values-and-masking). Request body, with the same masking support as headers. Map of output keys to response paths. See [ResponseMapping](/en/api-reference/actions-and-attributes#responsemapping-object). Optional explicit UUID for the new step. ## Response Returns the created [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object) with sensitive values masked. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/api-function-configs/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "stepNumber": 0, "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "responseMapping": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'requestUrl': 'https://help.example.com/refunds', 'requestMethod': 'GET', 'toolId': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', 'stepNumber': 0, 'requestHeaders': { 'name': 'Example', 'value': 'message' }, 'requestBody': { 'name': 'Example', 'value': 'message' }, 'responseMapping': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', 'id': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/api-function-configs/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "toolId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "stepNumber": 0, "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "responseMapping": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Lookup customer", "method": "GET", "url": "https://api.example.com/customers/{customerId}", "headers": { "Authorization": "Bearer ${apiToken}" }, "saveFromResponse": { "plan": "customer.plan", "status": "customer.status" }, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed or missing a required field. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while creating the Data Step in storage. # Create intent rule Source: https://docs.usefini.com/en/api-reference/create-intent-rule POST https://api-prod.usefini.com/v2/hc-rules/public Create a draft or published Rulebook intent rule. Creates an intent rule. Use `status: "DRAFT"` for a reviewable draft or `status: "PUBLISHED"` for a live version. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Rule name. Natural-language routing description used by the planner. Send `intent`. `DRAFT` or `PUBLISHED`. Defaults to `PUBLISHED`. `ARCHIVED` is rejected. Rule tree. See the shared [RuleNodeConfig](/en/api-reference/rules#rulenodeconfig-object) shape. Agent IDs to assign to a published rule. Drafts cannot include agent assignments. ## Response Returns the created [`Rule`](/en/api-reference/rules#rule-object). Draft responses have `botIds: []`. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "type": "intent", "status": "PUBLISHED", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'type': 'intent', 'status': 'PUBLISHED', 'flowConfig': { 'type': 'reply', 'message': 'Escalate refund requests with order context.' }, 'botIds': [ '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "type": "intent", "status": "PUBLISHED", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed, a draft includes agent assignments, an agent ID is invalid, or `flowConfig` references a missing action or widget form. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Create prompt draft version Source: https://docs.usefini.com/en/api-reference/create-prompt-draft-version POST https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/versions/public Create a draft prompt version for one agent without publishing it. Creates a draft prompt version for one agent and returns the stored draft version. Unlike [Update prompts](/en/api-reference/update-prompts), this route stores a version with `status: "DRAFT"`. Use this route when you want to stage prompt changes for review before they become the active prompt. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Agent ID whose prompt version you want to draft. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ## Body parameters Full Planning Prompt section array. Send the complete array, not just the section you changed. Full Main Guidelines section array. Full Channel Prompt section array. The body uses the same section shape as [Update prompts](/en/api-reference/update-prompts). The returned object is a prompt-version row with draft metadata, not the merged template view returned by [Get prompts](/en/api-reference/get-prompts). ## Response Returns the created draft prompt version. Draft prompt version ID. Prompt record ID this version belongs to. Agent ID the draft version belongs to. Version number assigned to the draft. Version status. This route returns `DRAFT`. Parent version used for stale-draft detection. Publication timestamp. Draft versions return `null`. Planning Prompt sections stored on the draft. Main Guidelines sections stored on the draft. Channel Prompt sections stored on the draft. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/versions/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "hcPlanningPrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcGuidelinePrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcChannelPrompt": [ "Answer only from approved knowledge and escalate if unsure." ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/versions/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'hcPlanningPrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ], 'hcGuidelinePrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ], 'hcChannelPrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/versions/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "hcPlanningPrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcGuidelinePrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcChannelPrompt": [ "Answer only from approved knowledge and escalate if unsure." ] }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "hcPlanningPrompt": [ { "id": "planning-main", "name": "Planning", "description": "How the agent plans an answer.", "enabled": true, "custom": true, "subsections": [ { "id": "planning-grounding", "name": "Grounding", "prompt": "Use approved knowledge before answering.", "defaultPrompt": "Use retrieved knowledge before answering.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcGuidelinePrompt": [ { "id": "guidelines-main", "name": "Main Guidelines", "description": "Global answer behavior.", "enabled": true, "custom": true, "subsections": [ { "id": "guidelines-escalation", "name": "Escalation", "prompt": "Escalate billing disputes when policy is unclear.", "defaultPrompt": "Escalate when unsure.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcChannelPrompt": [ { "id": "channel-chat", "name": "Chat", "description": "Chat-specific behavior.", "enabled": true, "custom": false, "subsections": [ { "id": "channel-chat-style", "name": "Tone", "prompt": "Keep replies concise and grounded in approved knowledge.", "defaultPrompt": "Keep replies helpful and concise.", "useDefault": false, "enabled": true, "custom": true } ] } ] } ``` ## Errors The body is malformed, the agent ID is invalid, or the current prompt is missing the prompt ID needed to create a draft version. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The agent belongs to a different workspace. Fini failed while creating the draft prompt version. # Delete action Source: https://docs.usefini.com/en/api-reference/delete-action DELETE https://api-prod.usefini.com/v2/hc-tools/{id}/public Delete one action. Deletes one action. This removes the record itself. Its Data Steps are separate records; delete them with [Delete data step](/en/api-reference/delete-data-step) if you no longer need them. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Action ID to delete. ## Response Returns `{ "success": true }` when the delete succeeds. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No action with that ID exists in your workspace. # Delete agent Source: https://docs.usefini.com/en/api-reference/delete-agent DELETE https://api-prod.usefini.com/v2/bots/{id}/public Delete one agent from the workspace. Deletes one agent in the workspace tied to your API key. Deleting an agent removes it from the workspace. Use [List agents](/en/api-reference/list-agents) first to confirm the ID and name before calling this route. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Agent ID to delete. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", { method: "DELETE", headers: { Authorization: "Bearer fini_your_api_key", }, } ); const result = await response.json(); ``` ## Response Returns a confirmation message. ```json 200 OK theme={null} { "message": "Bot Support Agent deleted" } ``` ## Errors The agent ID is not a valid UUID. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The agent does not exist in the API key's workspace. Fini failed while deleting the agent. # Delete attribute Source: https://docs.usefini.com/en/api-reference/delete-attribute DELETE https://api-prod.usefini.com/v2/hc-tools/{id}/public Delete one attribute. Deletes one attribute. It stops running for all agents it was assigned to. This removes the record itself. Its Data Steps are separate records; delete them with [Delete data step](/en/api-reference/delete-data-step) if you no longer need them. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Attribute ID to delete. ## Response Returns `{ "success": true }` when the delete succeeds. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No attribute with that ID exists in your workspace. # Delete external API call Source: https://docs.usefini.com/en/api-reference/delete-data-step DELETE https://api-prod.usefini.com/v2/api-function-configs/{id}/public Delete one external API call step. Deletes one external API call step from an action or attribute's chain. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters External API call step ID to delete. ## Response Returns `{ "success": boolean }`. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Delete intent rule Source: https://docs.usefini.com/en/api-reference/delete-intent-rule DELETE https://api-prod.usefini.com/v2/hc-rules/{id}/public Delete an intent rule and its agent assignments. Deletes an intent rule and removes its agent assignments. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Intent-rule ID to delete. ## Response Returns `204 No Content` when the delete succeeds. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The intent rule does not exist in your workspace. # Duplicate rule Source: https://docs.usefini.com/en/api-reference/duplicate-rule POST https://api-prod.usefini.com/v2/hc-rules/{id}/duplicate/public Copy an existing rule into a new rule with a new name and optional description. Duplicates an existing rule in the workspace. Use it to seed a new rule from a known-good Rulebook or Business Rule, then edit the copy before assigning or publishing it. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Rule ID to duplicate. ## Body parameters Name for the copied rule. Optional description for the copied rule. ## Response ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/duplicate/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes." }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/duplicate/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/duplicate/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes." }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` Returns the copied [`Rule`](/en/api-reference/rules#rule-object). # Evaluate rule Source: https://docs.usefini.com/en/api-reference/evaluate-rule POST https://api-prod.usefini.com/v2/hc-rules/{id}/evaluate/public Evaluate one rule against supplied input context and return rule-node results. Evaluates a rule directly from an input context payload. Use this when you want to test rule behavior without binding the evaluation to an existing conversation. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Rule ID to evaluate. ## Body parameters Input context to evaluate the rule against. Optional schema overrides for the evaluation. ## Response Returns an array of rule-node evaluation results. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "inputContext": { "name": "Example", "value": "message" }, "inputSchemaOverrides": { "name": "Example", "value": "message" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'inputContext': { 'name': 'Example', 'value': 'message' }, 'inputSchemaOverrides': { 'name': 'Example', 'value': 'message' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "inputContext": { "name": "Example", "value": "message" }, "inputSchemaOverrides": { "name": "Example", "value": "message" } }, ) data = response.json() ``` ```json 200 OK theme={null} { "matched": true, "path": [ "Refund escalation" ], "output": { "reply": "Escalate refund request with order context." } } ``` This route uses synthetic public-API test identifiers for the bot, trace, and session context. Use [Evaluate conversation rule](/en/api-reference/evaluate-conversation-rule) when you need to evaluate against a real conversation. # Generate intent-rule draft with AI Source: https://docs.usefini.com/en/api-reference/generate-intent-rule-draft POST https://api-prod.usefini.com/v2/hc-rules/generate/public Generate or refine intent-rule draft content with natural-language instructions and an LLM. Generates intent-rule draft content from natural-language instructions and the workspace's current fields context. The LLM returns a draft name, description, and rule tree. This endpoint supports intent rules only. It generates against the intent-rule fields context. The generated draft is not saved automatically. Persist the returned content with [Create intent rule](/en/api-reference/create-intent-rule) or [Update intent rule](/en/api-reference/update-intent-rule), using `status: "DRAFT"`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Natural-language instructions describing the rule to create or the changes to make. The value cannot be empty. Current rule name. Used as context when refining `currentFlowConfig`. Current rule description. Used as context when refining `currentFlowConfig`. Existing rule tree to refine. Omit it to generate a new draft from scratch. ## Response Generated draft content with `name`, `description`, and `flowConfig`. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/generate/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "instructions": "Create a draft rule that escalates refund requests with order context.", "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "currentFlowConfig": { "type": "reply", "message": "Escalate refund requests with order context." } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/generate/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'instructions': 'Create a draft rule that escalates refund requests with order context.', 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'currentFlowConfig': { 'type': 'reply', 'message': 'Escalate refund requests with order context.' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/generate/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "instructions": "Create a draft rule that escalates refund requests with order context.", "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "currentFlowConfig": { "type": "reply", "message": "Escalate refund requests with order context." } }, ) data = response.json() ``` ```json 200 OK theme={null} { "name": "Refund escalation", "description": "Escalate refund requests with order context.", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." } } ``` ## Errors `instructions` is empty, or `currentFlowConfig` is invalid. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini could not generate the draft content. # Generate Rulebook tests Source: https://docs.usefini.com/en/api-reference/generate-rulebook-tests POST https://api-prod.usefini.com/v2/hc-rules/generate-tests/public Generate suggested Rulebook test cases from a rule description, flow config, existing suite, and optional instructions. Generates suggested tests for a Rulebook flow. Use this as a draft helper when building coverage for a new or changed rule. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Description of the behavior the generated tests should cover. Rulebook flow configuration to generate tests against. Existing test suite context to avoid duplicate coverage. Additional instructions for the generator. ## Response Returns generated test-case suggestions for the supplied Rulebook flow. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/generate-tests/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "description": "Refund-policy conversations to re-check before prompt changes.", "flowConfig": { "name": "Example", "value": "message" }, "existingSuite": { "name": "Example", "value": "message" }, "instructions": "Create a draft rule that escalates refund requests with order context." }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/generate-tests/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'description': 'Refund-policy conversations to re-check before prompt changes.', 'flowConfig': { 'name': 'Example', 'value': 'message' }, 'existingSuite': { 'name': 'Example', 'value': 'message' }, 'instructions': 'Create a draft rule that escalates refund requests with order context.' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/generate-tests/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "description": "Refund-policy conversations to re-check before prompt changes.", "flowConfig": { "name": "Example", "value": "message" }, "existingSuite": { "name": "Example", "value": "message" }, "instructions": "Create a draft rule that escalates refund requests with order context." }, ) data = response.json() ``` ```json 200 OK theme={null} { "name": "Refund escalation", "description": "Escalate refund requests with order context.", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." } } ``` Generated tests are suggestions. Review them before adding them to a production regression suite. # Get action Source: https://docs.usefini.com/en/api-reference/get-action GET https://api-prod.usefini.com/v2/hc-tools/{id}/public Fetch one action by ID. Returns one [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object), including its `inputSchema` and `outputSchema`. For an action, expect `alwaysGet: false`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Action ID to fetch. ## Response Returns one [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Cancel subscription", "description": "Cancel an active subscription in billing.", "inputFields": [ { "name": "customerId", "type": "string", "required": true } ], "outputFields": [ { "name": "confirmationId", "type": "string" }, { "name": "effectiveDate", "type": "string" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. No action with that ID exists in your workspace. # Get agent analytics Source: https://docs.usefini.com/en/api-reference/get-agent-analytics GET https://api-prod.usefini.com/v2/bots/{id}/hc-analytics/public Fetch the full analytics summary for one agent. Returns analytics for one agent over a requested time window. The response includes summary metrics, comparison metrics, chart datasets, knowledge usage, rule analytics, escalation reasons, hourly volume, and CSAT data when available. Use this route when you need the complete analytics payload. If you only need one part of the payload, use [Get agent analytics section](/en/api-reference/get-agent-analytics-section). For the analytics endpoint family, see [Analytics](/en/api-reference/analytics). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID whose analytics you want to read. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ## Query parameters Start of the analytics window as a Unix epoch timestamp. End of the analytics window as a Unix epoch timestamp. Conversation source filter. Pass `all` to include all supported sources, or pass one or more source values accepted by Fini. Optional channel filter. Optional latest-status filter. Optional latest-sentiment filter. Optional knowledge subfolder IDs to filter by. Optional tag IDs to filter by. Optional rule IDs to filter by. Optional escalation-reason tag IDs to filter by. Optional CSAT ratings to filter by. Values must be integers from `1` through `5`. Optional timezone used for date grouping. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/public?startEpoch=1784073600000&endEpoch=1784678400000&source=all' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/public", headers={"Authorization": "Bearer fini_your_api_key"}, params={ "startEpoch": 1784073600000, "endEpoch": 1784678400000, "source": "all", }, ) analytics = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams({ startEpoch: "1784073600000", endEpoch: "1784678400000", source: "all", }); const response = await fetch( `https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/public?${params.toString()}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const analytics = await response.json(); ``` ```json 200 OK theme={null} { "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "range": { "from": "2026-07-01T00:00:00.000Z", "to": "2026-07-28T00:00:00.000Z" }, "overview": { "totalConversations": 1240, "escalationRate": 0.18, "resolutionRate": 0.74 }, "sections": [ { "id": "escalations", "title": "Escalations", "value": 223, "trend": "down" } ] } ``` ## Response Returns an `AgentAnalyticsSummary` object. Current-window totals and rates. Comparison-window totals and rates. Metric-card values for conversation volume, AI resolution rate, human escalation rate, average response time, and average CSAT rating. Conversation counts grouped by status. Conversation counts and resolved counts grouped by channel. Daily resolved, escalated, and waiting-for-customer counts. Daily total conversations, resolved conversations, and AI resolution rate. Daily average first-response time in milliseconds. Current and comparison knowledge-folder usage arrays. Rule-level conversation, resolution, escalation, and CSAT metrics. Escalation-reason tag counts. Volume by day of week and hour. Optional daily CSAT percentage chart data. ## AnalyticsMetrics object Total conversations in the window. Conversations resolved by AI. Conversations escalated to a human. Conversations waiting for the customer. AI resolution rate for the window. Human escalation rate for the window. Average response time in milliseconds. Average CSAT rating. ## Errors The path ID or query parameters are invalid. `startEpoch` and `endEpoch` are required. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The agent belongs to a different workspace. Fini failed while loading analytics. # Get agent analytics section Source: https://docs.usefini.com/en/api-reference/get-agent-analytics-section GET https://api-prod.usefini.com/v2/bots/{id}/hc-analytics/{section}/public Fetch one analytics section for one agent. Returns one section of the analytics summary for one agent. The accepted section values are `summary`, `trends`, `knowledge`, `rules`, and `escalations`. Use this route when you only need part of the analytics payload. Use [Get agent analytics](/en/api-reference/get-agent-analytics) when you need the full summary object. For the analytics endpoint family, see [Analytics](/en/api-reference/analytics). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID whose analytics you want to read. Use [List agents](/en/api-reference/list-agents) to get the `botId`. Analytics section to return. Accepted values are `summary`, `trends`, `knowledge`, `rules`, and `escalations`. ## Query parameters Start of the analytics window as a Unix epoch timestamp. End of the analytics window as a Unix epoch timestamp. Conversation source filter. Pass `all` to include all supported sources, or pass one or more source values accepted by Fini. Optional channel filter. Optional latest-status filter. Optional latest-sentiment filter. Optional knowledge subfolder IDs to filter by. Optional tag IDs to filter by. Optional rule IDs to filter by. Optional escalation-reason tag IDs to filter by. Optional CSAT ratings to filter by. Values must be integers from `1` through `5`. Optional timezone used for date grouping. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/summary/public?startEpoch=1784073600000&endEpoch=1784678400000&source=all' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/summary/public", headers={"Authorization": "Bearer fini_your_api_key"}, params={ "startEpoch": 1784073600000, "endEpoch": 1784678400000, "source": "all", }, ) section = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams({ startEpoch: "1784073600000", endEpoch: "1784678400000", source: "all", }); const response = await fetch( `https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-analytics/summary/public?${params.toString()}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const section = await response.json(); ``` ```json 200 OK theme={null} { "id": "escalations", "title": "Escalations", "value": 223, "trend": "down", "series": [ { "date": "2026-07-28", "value": 12 } ] } ``` ## Response Returns a partial analytics summary object for the requested section. | Section | Included fields | | ------------- | ------------------------------------------------------------------------------------------- | | `summary` | Summary metrics, comparison metrics, summary cards, status breakdown, and usage by channel. | | `trends` | Conversation-volume, resolution-rate, response-time, hourly-volume, and CSAT chart data. | | `knowledge` | Knowledge usage data. | | `rules` | Rule analytics data. | | `escalations` | Escalation-reason data. | See [Get agent analytics](/en/api-reference/get-agent-analytics) for the field-level analytics schema. ## Errors The path ID, section, or query parameters are invalid. `startEpoch` and `endEpoch` are required. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The agent belongs to a different workspace. Fini failed while loading analytics. # Get attribute Source: https://docs.usefini.com/en/api-reference/get-attribute GET https://api-prod.usefini.com/v2/hc-tools/{id}/public Fetch one attribute by ID. Returns one [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object), including its `inputSchema` and `outputSchema`. For an attribute, expect `alwaysGet: true`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Attribute ID to fetch. ## Response Returns one [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). Check `sendToLlm` on each `outputSchema` field to see which values are visible to the agent. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Customer plan", "description": "Fetches the customer's active plan.", "source": "widget", "fields": [ { "name": "plan", "type": "string", "visibleToAi": true, "useInRulebooks": true } ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. No attribute with that ID exists in your workspace. # Get external API call Source: https://docs.usefini.com/en/api-reference/get-data-step GET https://api-prod.usefini.com/v2/api-function-configs/{id}/public Fetch one external API call step by ID. Returns one external API call record with sensitive values masked. The wire-format object is still called [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters External API call step ID to fetch. ## Response Returns one [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object). ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Lookup customer", "method": "GET", "url": "https://api.example.com/customers/{customerId}", "headers": { "Authorization": "Bearer ${apiToken}" }, "saveFromResponse": { "plan": "customer.plan", "status": "customer.status" }, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading the Data Step, for example when the ID does not exist or is not a valid ID. # Get intent rule Source: https://docs.usefini.com/en/api-reference/get-intent-rule GET https://api-prod.usefini.com/v2/hc-rules/{id}/public Fetch a draft or published intent rule with its full tree. Returns one intent rule as a full [`Rule`](/en/api-reference/rules#rule-object). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Intent-rule ID. ## Query parameters Version to fetch. Use `DRAFT` or `PUBLISHED`. If omitted, the route returns the published version when one exists, otherwise the latest draft. ## Response Returns the rule with its `flowConfig` and lifecycle fields. Draft responses have `botIds: []`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public?versionStatus=PUBLISHED' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public?versionStatus=PUBLISHED', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public?versionStatus=PUBLISHED", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` Fetch archived snapshots by `versionId` through [Get intent-rule version](/en/api-reference/get-rule-version). ## Errors `versionStatus` is unsupported. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The intent rule or requested version does not exist in your workspace. # Get intent-rule fields context Source: https://docs.usefini.com/en/api-reference/get-intent-rule-fields-context GET https://api-prod.usefini.com/v2/hc-rules/fields-context/public Get the fields and resources available to intent-rule trees. Returns the workspace attributes, actions, tags, forms, operators, and sources that can be referenced by an intent-rule tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Send `intent`. ## Response Workspace user attributes with their input and output schemas. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "contextFields": [ { "path": "message.text", "dataType": "string" }, { "path": "user.email", "dataType": "string" } ], "operatorTypes": [ "==", "!=", "contains" ], "quantifierTypes": [ "ANY", "ALL", "NONE" ] } ``` Workspace actions available to Tool nodes. Fini-provided actions available to Tool nodes. Input tag groups and their tags. Widget forms and their typed fields. Empty for intent rules. Condition operators as `{ value, label }` objects. Array quantifiers as `{ value, label }` objects. Interaction sources available in the workspace. ## Errors `type` is not a supported rule type. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. # Get prompt draft version Source: https://docs.usefini.com/en/api-reference/get-prompt-draft-version GET https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/versions/{versionId}/public Fetch one exact stored prompt draft version for review. Returns one stored prompt lifecycle version for an agent. Use this route to review the complete prompt arrays and metadata for a draft before publishing it. Unlike [Get prompts](/en/api-reference/get-prompts), this route does not merge the current prompt with the workspace template. It returns the exact stored version identified by `versionId`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID that owns the prompt version. Prompt lifecycle version ID returned by [Create prompt draft version](/en/api-reference/create-prompt-draft-version). ## Response Prompt lifecycle version ID. Prompt record ID this lifecycle version is based on. Agent ID that owns the version. Agent-specific lifecycle version number. Current lifecycle status. Published lifecycle version this draft was created from. Publication timestamp. Draft versions return `null`. Exact Planning Prompt sections stored on the version. Exact Main Guidelines sections stored on the version. Exact Channel Prompt sections stored on the version. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/versions/9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests agent_id = "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" version_id = "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e" response = requests.get( f"https://api-prod.usefini.com/v2/bots/{agent_id}/hc-prompt/versions/{version_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) prompt_version = response.json() ``` ```javascript Node.js theme={null} const agentId = "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3"; const versionId = "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e"; const response = await fetch( `https://api-prod.usefini.com/v2/bots/${agentId}/hc-prompt/versions/${versionId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const promptVersion = await response.json(); ``` ```json 200 OK theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "promptId": "6d5ab04e-6d45-45f3-84a1-5822657be9aa", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "versionNumber": 12, "status": "DRAFT", "parentVersionId": "f15be201-60d8-4c7d-8b5b-66c2b7a62c34", "publishedAt": null, "hcPlanningPrompt": [ { "id": "planning", "title": "Planning Prompt", "content": "Decide whether to search knowledge before answering." } ], "hcGuidelinePrompt": [ { "id": "main-guidelines", "title": "Main Guidelines", "content": "Answer with the approved refund policy." } ], "hcChannelPrompt": [ { "id": "widget", "title": "Widget", "content": "Keep widget replies concise." } ] } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include `read` scope. The version does not exist for this agent. The agent belongs to a different workspace. # Get prompt history Source: https://docs.usefini.com/en/api-reference/get-prompt-history GET https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/history/public List metadata for an agent's saved prompt versions, newest first. Returns metadata for every saved prompt version for one agent, ordered by `createdAt` descending. The response does not include prompt section arrays. This history is agent-specific. It does not synthesize the workspace template as a history entry, so agents with no saved prompt versions return an empty array rather than a template row. Pass a returned `id` to [Get prompt version](/en/api-reference/get-prompt-version) to fetch that version's full merged prompt object. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID whose prompt history you want to read. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ## Response Returns a top-level array of prompt-version metadata objects, newest first. Prompt version ID. Pass this value as `promptId` to [Get prompt version](/en/api-reference/get-prompt-version). Agent ID the saved version belongs to. ISO 8601 timestamp for when the prompt version was created. Creator identifier recorded for the saved version. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/history/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/history/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/history/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "a8b2a418-6f33-4f40-9d1e-4b581fd34d5e", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "createdAt": "2026-07-21T06:12:31.456Z", "createdBy": "3d2abf0c-d80f-42cf-96e9-a2e26f18f0e8" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The agent ID does not exist. Current controller behavior: if the agent belongs to a different workspace, this route returns `406` with an invalid-agent message rather than `403`. Fini failed while loading prompt history from storage. # Get prompt version Source: https://docs.usefini.com/en/api-reference/get-prompt-version GET https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/{promptId}/public Fetch one saved prompt version for an agent. Returns one saved prompt version as a merged view of that version plus the current workspace template. Use [Get prompt history](/en/api-reference/get-prompt-history) to find saved `promptId` values. Template sections missing from the saved version are included in this response with merged-read helper fields such as `defaultPrompt` and `custom`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID that owns the prompt version. Use [List agents](/en/api-reference/list-agents) to get the `botId`. Saved prompt version ID returned by [Get prompt history](/en/api-reference/get-prompt-history). ## Response Returns one merged [`Prompt`](/en/api-reference/prompts#prompt-object) object. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "hcPlanningPrompt": [ { "id": "planning-main", "name": "Planning", "description": "How the agent plans an answer.", "enabled": true, "custom": true, "subsections": [ { "id": "planning-grounding", "name": "Grounding", "prompt": "Use approved knowledge before answering.", "defaultPrompt": "Use retrieved knowledge before answering.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcGuidelinePrompt": [ { "id": "guidelines-main", "name": "Main Guidelines", "description": "Global answer behavior.", "enabled": true, "custom": true, "subsections": [ { "id": "guidelines-escalation", "name": "Escalation", "prompt": "Escalate billing disputes when policy is unclear.", "defaultPrompt": "Escalate when unsure.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcChannelPrompt": [ { "id": "channel-chat", "name": "Chat", "description": "Chat-specific behavior.", "enabled": true, "custom": false, "subsections": [ { "id": "channel-chat-style", "name": "Tone", "prompt": "Keep replies concise and grounded in approved knowledge.", "defaultPrompt": "Keep replies helpful and concise.", "useDefault": false, "enabled": true, "custom": true } ] } ] } ``` ## Errors The agent ID or prompt version ID is not a valid UUID. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The agent ID does not exist. The agent belongs to a different workspace, or the prompt version does not belong to the agent in the path. Fini failed while loading the prompt version or workspace template. # Get prompts Source: https://docs.usefini.com/en/api-reference/get-prompts GET https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/public Fetch the current merged prompts for one agent. Returns the current prompt configuration for one agent as a merged view of the workspace template plus the agent's latest saved prompt version. If the agent has no saved prompt version yet, this route still returns prompt content by falling back to the workspace template. In that case, the metadata comes from the template prompt, but `botId` is still the requested agent ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Agent ID whose prompts you want to read. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ## Response Returns one merged [`Prompt`](/en/api-reference/prompts#prompt-object) object. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "hcPlanningPrompt": [ { "id": "planning-main", "name": "Planning", "description": "How the agent plans an answer.", "enabled": true, "custom": true, "subsections": [ { "id": "planning-grounding", "name": "Grounding", "prompt": "Use approved knowledge before answering.", "defaultPrompt": "Use retrieved knowledge before answering.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcGuidelinePrompt": [ { "id": "guidelines-main", "name": "Main Guidelines", "description": "Global answer behavior.", "enabled": true, "custom": true, "subsections": [ { "id": "guidelines-escalation", "name": "Escalation", "prompt": "Escalate billing disputes when policy is unclear.", "defaultPrompt": "Escalate when unsure.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcChannelPrompt": [ { "id": "channel-chat", "name": "Chat", "description": "Chat-specific behavior.", "enabled": true, "custom": false, "subsections": [ { "id": "channel-chat-style", "name": "Tone", "prompt": "Keep replies concise and grounded in approved knowledge.", "defaultPrompt": "Keep replies helpful and concise.", "useDefault": false, "enabled": true, "custom": true } ] } ] } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The agent ID does not exist. Current controller behavior: if the agent belongs to a different workspace, this route returns `406` with an invalid-agent message rather than `403`. Fini failed while loading the prompt data from storage. # Get rule test fields Source: https://docs.usefini.com/en/api-reference/get-rule-test-fields GET https://api-prod.usefini.com/v2/hc-rules/{id}/test-fields/public Return the fields available for testing one saved rule. Returns the test fields Fini derives from one saved rule. Use this to build a rule test form or validate which fields are required before running an evaluation. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Rule ID. ## Response ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-fields/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-fields/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-fields/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "contextFields": [ { "path": "message.text", "dataType": "string" }, { "path": "user.email", "dataType": "string" } ], "operatorTypes": [ "==", "!=", "contains" ], "quantifierTypes": [ "ANY", "ALL", "NONE" ] } ``` Returns an array of test field definitions. # Get intent-rule version Source: https://docs.usefini.com/en/api-reference/get-rule-version GET https://api-prod.usefini.com/v2/hc-rules/{id}/versions/{versionId}/public Get one intent-rule version with its full tree. Returns a specific historical, draft, or published version of an intent rule. This endpoint supports intent rules only. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Intent-rule ID. Version ID belonging to the rule. ## Response Returns one [`Rule version`](/en/api-reference/rules#rule-version-object), including `flowConfig`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "versionId": "v3", "version": 3, "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "item": { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } } ] ``` ## Errors A path parameter is empty, or the specified rule is a Business Rule. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The rule or version does not exist in your workspace, or the version does not belong to the rule. # Overview Source: https://docs.usefini.com/en/api-reference/intent-rules Create, version, generate, and publish Rulebook intent rules through the public API. Intent rules are the workflows configured under [Automations → Rulebook](/en/automations/rulebook). Send `type: "intent"` when creating them and `type=intent` when listing them. Intent rules have a version lifecycle. A rule can have a current published version, draft versions, and archived historical versions. Drafts have no agent assignments and do not run in production until published. ## Intent-rule endpoints ### Endpoints shared with Business Rules | Method | Path | Scope | Intent-rule usage | | -------- | ------------------------------------ | ------- | ------------------------------------------------------------------------------------------- | | `GET` | `/v2/hc-rules/public` | `read` | List with `type=intent`. Use `versionStatus` or `includeVersions` to select lifecycle data. | | `GET` | `/v2/hc-rules/fields-context/public` | `read` | Get available fields with `type=intent`. | | `GET` | `/v2/hc-rules/:id/public` | `read` | Get a draft or published rule tree. | | `POST` | `/v2/hc-rules/public` | `write` | Create with `type: "intent"` and `status: "DRAFT"` or `"PUBLISHED"`. | | `PATCH` | `/v2/hc-rules/:id/public` | `write` | Create a new draft or published version. | | `DELETE` | `/v2/hc-rules/:id/public` | `write` | Delete the rule and its agent assignments. | ### Intent-only endpoints | Method | Path | Scope | Purpose | | ------ | -------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------- | | `POST` | `/v2/hc-rules/generate/public` | `write` | Use natural-language instructions and an LLM to generate or refine draft rule content. | | `GET` | `/v2/hc-rules/:id/versions/public` | `read` | List draft, published, and archived versions. | | `GET` | `/v2/hc-rules/:id/versions/:versionId/public` | `read` | Get one version with its full tree. | | `POST` | `/v2/hc-rules/:id/publish/public` | `write` | Publish a selected draft version and assign agents. | | `POST` | `/v2/hc-rules/:id/versions/:versionId/restore-as-draft/public` | `write` | Copy any historical version into a new draft. | ## Typical draft workflow Call [Generate intent-rule draft with AI](/en/api-reference/generate-intent-rule-draft) with natural-language instructions. The LLM returns a draft name, description, and rule tree. The response is not persisted yet. Call [Create intent rule](/en/api-reference/create-intent-rule) with `status: "DRAFT"` and the generated fields or your own tree. Do not send `botIds` for a draft. Call [Update intent rule](/en/api-reference/update-intent-rule) with `status: "DRAFT"`. Sending the status explicitly prevents an existing published version from being updated instead. Read the draft's `versionId`, then call [Publish rule draft](/en/api-reference/publish-rule-draft) with that `draftVersionId` and at least one agent ID. A draft becomes stale when its `parentVersionId` no longer matches the current published version. The publish route rejects stale drafts. Restore or recreate the draft from the current version before publishing. ## Intent-rule response fields Intent-rule responses use the shared [`Rule`](/en/api-reference/rules#rule-object) shape and add lifecycle fields such as `version`, `versionId`, `status`, `parentVersionId`, `publishedAt`, `isStale`, and `currentPublishedVersionId`. # List agent assignments Source: https://docs.usefini.com/en/api-reference/list-action-agents GET https://api-prod.usefini.com/v2/hc-tools/{id}/junctions/public List the agents an action is assigned to. Returns the agent assignments for one action. Action assignments are stored but not enforced at runtime; whether an agent can invoke an action is decided by [Rulebook](/en/automations/rulebook) wiring and the rule's own agent assignments. See [Assign to agents](/en/api-reference/assign-action-agents). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Action ID whose assignments you want. ## Response Returns a top-level array of [`Agent assignment`](/en/api-reference/actions-and-attributes#agent-assignment-object) objects. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Cancel subscription", "description": "Cancel an active subscription in billing.", "inputFields": [ { "name": "customerId", "type": "string", "required": true } ], "outputFields": [ { "name": "confirmationId", "type": "string" }, { "name": "effectiveDate", "type": "string" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. # List actions Source: https://docs.usefini.com/en/api-reference/list-actions GET https://api-prod.usefini.com/v2/hc-tools/public List the actions in the workspace. Returns every [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object) record in the workspace, newest first. Actions are the records with `alwaysGet: false`. Actions and attributes share this endpoint, so the array contains both. Filter on `alwaysGet: false` to keep only actions. See [List attributes](/en/api-reference/list-attributes) for the attribute view of the same route. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Returns a top-level array of [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object) objects. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Cancel subscription", "description": "Cancel an active subscription in billing.", "inputFields": [ { "name": "customerId", "type": "string", "required": true } ], "outputFields": [ { "name": "confirmationId", "type": "string" }, { "name": "effectiveDate", "type": "string" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading records from storage. # List agents Source: https://docs.usefini.com/en/api-reference/list-agents GET https://api-prod.usefini.com/v2/bots/public List workspace agents with their IDs and serialized prompt text. Returns every non-deleted agent in the workspace tied to your API key, sorted by most recently updated first. Each item includes the agent ID, name, creation timestamp, and serialized planning, guideline, email-channel, and chat-channel prompts. Use this endpoint to look up the `botId` values accepted by [List conversations](/en/api-reference/list-conversations), [Generate Answer](/en/api-reference/generate-answer), and other public routes that scope behavior to one agent. For structured prompt sections, use [Get prompts](/en/api-reference/get-prompts). For the full agent endpoint family, including create and delete routes, see [Agents](/en/api-reference/agents). Use [Analytics](/en/api-reference/analytics) for agent-level reporting endpoints and [Prompts](/en/api-reference/prompts) for prompt-version routes. This endpoint returns all agents in a single response, there is no pagination, filtering, or limit. The endpoint path uses `/bots` because that is the current API contract. In the dashboard and the rest of these docs, the same workspace entities are called agents. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/bots/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/bots/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) agents = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/bots/public", { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const agents = await response.json(); ``` ## Response The response is a top-level array of agent objects. Array of agents in the workspace. The agent's `botId`. Pass this value as `botId` on endpoints that support agent-level filtering. Agent name as configured in the workspace. ISO 8601 timestamp for when the agent was created. Serialized planning prompt built from enabled planning sections and subsections. Serialized main-guidelines prompt built from enabled guideline sections and subsections. Serialized prompt for enabled email-channel sections. An empty string means no enabled email prompt content is available. Serialized prompt for enabled chat-channel sections. An empty string means no enabled chat prompt content is available. The four prompt fields are rendered strings intended for inspection or downstream text use. They include enabled prompt sections serialized from the agent prompt configuration. To edit prompts or preserve section IDs and ordering, read the structured arrays from [Get prompts](/en/api-reference/get-prompts). ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Support Agent", "createdAt": "2026-05-20T12:34:56.789Z", "hcPlanningPrompt": "\n\n## PLAN THE RESPONSE\n...\n\n\n\n\n", "hcGuidelinePrompt": "
\n\n## ANSWER ACCURATELY\n...\n\n
\n\n\n", "hcEmailChannelPrompt": "\n\n## FORMAT\n...\n\n\n\n\n", "hcChatChannelPrompt": "\n\n## FORMAT\n...\n\n\n\n\n" }, { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "name": "Billing Agent", "createdAt": "2026-05-12T08:41:10.201Z", "hcPlanningPrompt": "\n\n## PLAN THE RESPONSE\n...\n\n\n\n\n", "hcGuidelinePrompt": "
\n\n## ANSWER ACCURATELY\n...\n\n
\n\n\n", "hcEmailChannelPrompt": "", "hcChatChannelPrompt": "\n\n## FORMAT\n...\n\n\n\n\n" } ] ``` ```json 401 Unauthorized theme={null} { "statusCode": 401, "message": "Invalid or revoked API key", "error": "Unauthorized" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ```
## Errors The workspace API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The key is valid but doesn't include the `read` scope, or it's scoped to a different workspace. The key's workspace has no non-deleted agents available to the public route. Create an agent in the dashboard or confirm you're authenticating against the right workspace. # List agent assignments Source: https://docs.usefini.com/en/api-reference/list-attribute-agents GET https://api-prod.usefini.com/v2/hc-tools/{id}/junctions/public List the agents an attribute is assigned to. Returns the agent assignments for one attribute. Assignments are what make an attribute run for an agent's conversations. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Attribute ID whose assignments you want. ## Response Returns a top-level array of [`Agent assignment`](/en/api-reference/actions-and-attributes#agent-assignment-object) objects. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/junctions/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Customer plan", "description": "Fetches the customer's active plan.", "source": "widget", "fields": [ { "name": "plan", "type": "string", "visibleToAi": true, "useInRulebooks": true } ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. # List attributes Source: https://docs.usefini.com/en/api-reference/list-attributes GET https://api-prod.usefini.com/v2/hc-tools/public List the attributes in the workspace. Returns every [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object) record in the workspace, newest first. Attributes are the records with `alwaysGet: true`. Actions and attributes share this endpoint, so the array contains both. Filter on `alwaysGet: true` to keep only attributes. See [List actions](/en/api-reference/list-actions) for the action view of the same route. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Returns a top-level array of [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object) objects. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-tools/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-tools/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Customer plan", "description": "Fetches the customer's active plan.", "source": "widget", "fields": [ { "name": "plan", "type": "string", "visibleToAi": true, "useInRulebooks": true } ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading records from storage. # List external API calls Source: https://docs.usefini.com/en/api-reference/list-data-steps GET https://api-prod.usefini.com/v2/api-function-configs/public List external API call steps, optionally filtered by action or attribute. Returns external API call records in the workspace. The wire-format object is still called [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object). Pass `toolId` to list only the calls for one action or attribute, ordered by `stepNumber`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Optional action or attribute ID. When set, returns only that record's external API calls, ordered by `stepNumber`. ## Response Returns a top-level array of [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object) objects with sensitive values masked. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/api-function-configs/public?toolId=4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/public?toolId=4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/api-function-configs/public?toolId=4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Lookup customer", "method": "GET", "url": "https://api.example.com/customers/{customerId}", "headers": { "Authorization": "Bearer ${apiToken}" }, "saveFromResponse": { "plan": "customer.plan", "status": "customer.status" }, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading Data Steps, for example when `toolId` is not a valid ID. # List intent rules Source: https://docs.usefini.com/en/api-reference/list-intent-rules GET https://api-prod.usefini.com/v2/hc-rules/public List Rulebook intent rules by version status. Returns intent rules in the workspace as summary objects. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Send `intent`. Version state to return: `DRAFT`, `PUBLISHED`, or `ARCHIVED`. Defaults to `PUBLISHED`. Set to `true` to include `botIds`, current-published metadata, latest-draft metadata, `draftCount`, and `lastPublishedAt`. Defaults to `false`. ## Response Returns an array of [`Rule summary`](/en/api-reference/rules#rule-summary-object) objects without `flowConfig`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/public?type=intent&versionStatus=PUBLISHED&includeVersions=True' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/public?type=intent&versionStatus=PUBLISHED&includeVersions=True', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/public?type=intent&versionStatus=PUBLISHED&includeVersions=True", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ### Fields added by `includeVersions=true` The active published version, or `null` when the rule has not been published. Uses the shared [`Rule version`](/en/api-reference/rules#rule-version-object) shape without `flowConfig`. The most recent draft version, or `null` when the rule has no draft. Uses the shared [`Rule version`](/en/api-reference/rules#rule-version-object) shape without `flowConfig`. Number of draft revisions represented by the latest draft relative to the current published version. ISO 8601 publication timestamp for the current published version. If its publication timestamp is unavailable, the API uses that version's last-update timestamp. Returns `null` when the rule has not been published. With `includeVersions=false`, intent-rule summaries omit `botIds`. Use `includeVersions=true` for a lifecycle overview, or [Get intent rule](/en/api-reference/get-intent-rule) for the full tree. ## Errors A query parameter is malformed or uses an unsupported enum value. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading intent rules. # List intent-rule versions Source: https://docs.usefini.com/en/api-reference/list-rule-versions GET https://api-prod.usefini.com/v2/hc-rules/{id}/versions/public List every version of an intent rule. Returns the version history for one intent rule. Business Rules do not support this route. This endpoint supports intent rules only. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Intent-rule ID. ## Response Rule ID. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "versionId": "v3", "version": 3, "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "item": { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } } ] ``` Active published version ID. Version history. Each item uses the shared [`Rule version`](/en/api-reference/rules#rule-version-object) shape without `flowConfig`. ## Errors The specified rule is a Business Rule. Version routes support intent rules only. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The rule does not exist in your workspace. # Preview rule test fields Source: https://docs.usefini.com/en/api-reference/preview-rule-test-fields POST https://api-prod.usefini.com/v2/hc-rules/test-fields/preview/public Preview test fields for an unsaved Rulebook flow configuration. Derives test fields from a flow configuration payload without requiring the rule to be saved first. Use this while building or editing a rule draft. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. `application/json` ## Body parameters Rulebook flow configuration to inspect. ## Response ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/test-fields/preview/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "flowConfig": { "name": "Example", "value": "message" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/test-fields/preview/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'flowConfig': { 'name': 'Example', 'value': 'message' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/test-fields/preview/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "flowConfig": { "name": "Example", "value": "message" } }, ) data = response.json() ``` ```json 200 OK theme={null} { "contextFields": [ { "path": "message.text", "dataType": "string" }, { "path": "user.email", "dataType": "string" } ], "operatorTypes": [ "==", "!=", "contains" ], "quantifierTypes": [ "ANY", "ALL", "NONE" ] } ``` Returns an array of test field definitions. # Overview Source: https://docs.usefini.com/en/api-reference/prompts Section hub for reading prompt configuration and saving prompt versions through Fini's public API. Prompts are the instruction layers behind [Configuration → Prompts](/en/configuration/prompts): planning, main guidelines, and channel-specific overrides. Use these public routes to read one agent's current prompt configuration, inspect saved prompt history, save a new prompt version, or stage a draft prompt version for review. The wire-format paths still use `/hc-prompt` because that is the current controller contract. In this reference, we call them **prompts** because they manage the agent instructions you configure in the product. The read routes return a merged view: Fini overlays the agent's saved prompt version on top of the workspace template prompt. That is why read responses include helper fields like `defaultPrompt` and `custom`. The write route stores a raw version payload and does not perform that merge in its response. ## Reference pages `GET /v2/bots/{id}/hc-prompt/public` - fetch the agent's current merged prompt configuration. `GET /v2/bots/{id}/hc-prompt/history/public` - list metadata for saved prompt versions. `GET /v2/bots/{id}/hc-prompt/{promptId}/public` - fetch one saved prompt version as a merged prompt object. `POST /v2/bots/{id}/hc-prompt/public` - save a new prompt version for one agent. `POST /v2/bots/{id}/hc-prompt/versions/public` - create a draft prompt version without publishing it. `GET /v2/bots/{id}/hc-prompt/versions/{versionId}/public` - fetch one exact stored draft version for review. `POST /v2/bots/{id}/hc-prompt/versions/{versionId}/publish/public` - publish one reviewed draft version. ## Endpoint map | Method | Path | Scope | Purpose | | ------ | ----------------------------------------------------------- | ------- | --------------------------------------------------------------- | | `GET` | `/v2/bots/:id/hc-prompt/public` | `read` | Fetch the current merged prompts for one agent. | | `GET` | `/v2/bots/:id/hc-prompt/history/public` | `read` | List saved prompt-version metadata for one agent, newest first. | | `GET` | `/v2/bots/:id/hc-prompt/:promptId/public` | `read` | Fetch one saved prompt version as a merged prompt object. | | `POST` | `/v2/bots/:id/hc-prompt/public` | `write` | Save a new prompt version for one agent. | | `POST` | `/v2/bots/:id/hc-prompt/versions/public` | `write` | Create a draft prompt version for one agent. | | `GET` | `/v2/bots/:id/hc-prompt/versions/:versionId/public` | `read` | Fetch one exact stored draft version for review. | | `POST` | `/v2/bots/:id/hc-prompt/versions/:versionId/publish/public` | `write` | Publish one reviewed, non-stale draft version. | ## Prompt object Prompt version ID. On read routes, this is the saved version ID when one exists, otherwise the template prompt ID. Agent ID the prompt is scoped to. ISO 8601 timestamp for when this prompt version was created. Creator identifier recorded for the saved version. Planning Prompt sections. Main Guidelines sections. Channel Prompt sections. ## PromptSection object Section ID. Section name shown in the dashboard. Section description. Whether the section is enabled. Present on merged read responses. `true` means this section does not come from the default template. Subsections inside the section. ## PromptSubsection object Subsection ID. Subsection name shown in the dashboard. The saved custom prompt text for this subsection. On merged read responses, this can be an empty string when `useDefault` is `true`. Present on merged read responses. The default template text Fini would use if `useDefault` is `true`. Whether this subsection should use the template prompt text instead of the custom `prompt` value. Whether the subsection is enabled. Present on merged read responses. `true` means this subsection does not come from the default template. If you want to edit prompts safely through the API, the simplest workflow is: call [Get prompts](/en/api-reference/get-prompts), modify the returned arrays, then send those arrays back to [Update prompts](/en/api-reference/update-prompts). That preserves section IDs and ordering. # Publish prompt draft version Source: https://docs.usefini.com/en/api-reference/publish-prompt-draft-version POST https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/versions/{versionId}/publish/public Publish one reviewed prompt draft version. Publishes one exact prompt draft version and makes its three prompt arrays the agent's active configuration. Before calling this route, fetch the version with [Get prompt draft version](/en/api-reference/get-prompt-draft-version), compare it with [Get prompts](/en/api-reference/get-prompts), and obtain explicit confirmation for that agent and version. Publishing changes live agent behavior. A draft becomes stale when the published prompt changes after the draft was created. Fini rejects stale drafts instead of overwriting the newer configuration. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Agent ID that owns the draft. Exact reviewed draft version ID to publish. ## Response Returns the published lifecycle version. Published lifecycle version ID. This matches `versionId`. New active prompt record ID created from the draft. Agent ID that now uses the published prompt. Published lifecycle version number. Returns `PUBLISHED`. Publication timestamp. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/versions/9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e/publish/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests agent_id = "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" version_id = "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e" response = requests.post( f"https://api-prod.usefini.com/v2/bots/{agent_id}/hc-prompt/versions/{version_id}/publish/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) published_version = response.json() ``` ```javascript Node.js theme={null} const agentId = "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3"; const versionId = "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e"; const response = await fetch( `https://api-prod.usefini.com/v2/bots/${agentId}/hc-prompt/versions/${versionId}/publish/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", }, } ); const publishedVersion = await response.json(); ``` ```json 200 OK theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "promptId": "a6d8c1df-df4c-4307-8c0f-41f7ac0c2ca7", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "versionNumber": 12, "status": "PUBLISHED", "publishedAt": "2026-08-01T09:14:00.000Z" } ``` ## Errors The draft is stale because a different prompt version became published after this draft was created. The API key is missing, malformed, revoked, or invalid. The API key does not include `write` scope. The version does not exist for this agent or is not a draft. The agent belongs to a different workspace. # Publish intent-rule draft Source: https://docs.usefini.com/en/api-reference/publish-rule-draft POST https://api-prod.usefini.com/v2/hc-rules/{id}/publish/public Publish an intent-rule draft and assign it to one or more agents. Publishes one draft [`Rule`](/en/api-reference/rules#rule-object) and assigns it to one or more agents. This endpoint supports intent rules only. Business Rules are published immediately when created and do not have drafts. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Draft rule ID to publish. ## Body parameters Agent IDs to assign after publishing. At least one ID is required. UUID of the draft version to publish. Get it from [List intent-rule versions](/en/api-reference/list-rule-versions) or a `versionStatus=DRAFT` [Get intent rule](/en/api-reference/get-intent-rule) response. ## Response Returns the published [`Rule`](/en/api-reference/rules#rule-object). ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "draftVersionId": "v3" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'botIds': [ '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312' ], 'draftVersionId': 'v3' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "draftVersionId": "v3" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed, the `botIds` array is empty, one or more agent IDs do not belong to your workspace, or the selected draft became stale after another version was published. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The draft rule or `draftVersionId` does not exist in your workspace, does not belong to the rule, or is no longer a draft. Fini failed while publishing the draft or syncing agent assignments. # Restore intent-rule version as draft Source: https://docs.usefini.com/en/api-reference/restore-rule-version-as-draft POST https://api-prod.usefini.com/v2/hc-rules/{id}/versions/{versionId}/restore-as-draft/public Copy an intent-rule version into a new draft. Creates a new draft from any version of an intent rule. The source version is unchanged. This endpoint supports intent rules only. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Intent-rule ID. Version to copy into a new draft. ## Response Returns `201 Created` with the new draft [`Rule`](/en/api-reference/rules#rule-object). The response has `status: "DRAFT"` and `botIds: []`. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/restore-as-draft/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/restore-as-draft/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/versions/v3/restore-as-draft/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "versionId": "v3", "version": 3, "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "item": { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } } ] ``` The new draft's `parentVersionId` is the rule's current published version, not necessarily the restored source version. This is what the service uses to detect stale drafts before publication. ## Errors A path parameter is empty, or the specified rule is a Business Rule. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The rule or version does not exist in your workspace, or the version does not belong to the rule. # Overview Source: https://docs.usefini.com/en/api-reference/rules Read, manage, version, and generate rules through Fini's public API. The Rules API manages two resources with different lifecycles: versioned intent rules and unversioned Business Rules. Every endpoint in this section uses a workspace API key. The API paths use `/hc-rules`, which is the current controller contract. This reference calls these resources **rules** to match the product. Rulebook workflows with drafts, published versions, version history, generation, and restore. Widget-escalation workflows with custom and Fini-provided template modes. Run a saved rule against supplied input context and inspect node results. Generate suggested test cases from a Rulebook flow. ## Endpoint relevance | Endpoint family | Intent rules | Business Rules | | ------------------------------------------------- | ------------- | -------------- | | List, get, fields context, create, update, delete | Supported | Supported | | Duplicate and direct evaluation | Supported | Supported | | Test-field preview and extraction | Supported | Supported | | Generate draft content with an LLM | Supported | Not supported | | Generate Rulebook tests | Supported | Not supported | | Version history, publish draft, restore as draft | Supported | Not supported | | Default templates | Not supported | Supported | The six endpoints that support both rule types share paths. Use `type=intent` or `type=business` on list and fields-context requests, and send the `type` explicitly when creating a rule. ## Rule summary object List and default-template routes return rule summaries without `flowConfig`. ### Fields shared by both rule types Rule ID. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Workspace ID. Fini-provided default templates use `null`. Rule name. Natural-language rule description. ### Intent-rule lifecycle fields Whether the resolved intent-rule version is a draft. Resolved version number for an intent rule. Resolved version ID for an intent rule. Version status. Current values are `DRAFT`, `PUBLISHED`, and `ARCHIVED`. Published version from which a draft was created. ISO 8601 publication timestamp. Whether a draft is based on an older published version. Current published version ID. ### Assignment and type fields Assigned agent IDs when the selected list mode includes assignments. `intent` or `business`. ### Business Rule configuration fields Fini-provided template used by this rule, if any. Rule source. The current enum value is `widget`. Business-rule trigger. The current enum value is `on_escalation`. Optional runtime input schema. ## Rule object The full rule object includes every applicable rule-summary field plus these fields: Full rule tree. Agent IDs assigned to the rule. Draft responses return an empty array. ## Rule version object Rule version objects apply only to intent rules. Version ID. Parent rule ID. Monotonically increasing version number. `DRAFT`, `PUBLISHED`, or `ARCHIVED`. Name captured in this version. Description captured in this version. Published version on which this version is based. ISO 8601 publication timestamp. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Whether this is the rule's active published version. Whether this draft is based on an older published version. Full version tree. Present on the get-version route and omitted from version-list items. ## RuleNodeConfig object Root node ID. Map of node IDs to node configs. Every node has `id`, `name`, and `type`, plus fields specific to that node type. Current node types are `SEQUENCE`, `SELECTOR`, `CONDITION`, `ACTION`, and `WIDGET_FORM_RENDERER`. Current action subtypes are `LLM_EXTRACTION`, `TOOL_CALL`, `PROMPT_INJECTION`, `WIDGET_FORM_VALIDATION_ERROR`, and `SEND_MESSAGE`. ## InputSchemaField object Field name. `string`, `number`, `boolean`, `array`, `object`, or `date`. Whether the field is required. Optional runtime path to bind from. Optional literal value. Optional source: `metadata`, `jwt`, or `apiResponse`. Optional fallback value. Optional context path to bind automatically. Rule creation and update validate referenced agent IDs, actions, and widget forms. Template-based rules cannot define their own `flowConfig`. # Test action Source: https://docs.usefini.com/en/api-reference/test-action POST https://api-prod.usefini.com/v2/hc-tools/{id}/test-run/public Run the whole action with sample inputs. Runs the full Data Step chain for one action against sample inputs and returns the resolved outputs. This mirrors the dashboard Run button. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Action ID to run. ## Body parameters Optional sample inputs, keyed by input field name. These stand in for the runtime values a rule would pass when it invokes the action. ## Response Returns an [`Action / Attribute test-run result`](/en/api-reference/actions-and-attributes#action-or-attribute-test-run-result) with per-step results and the final `extractedData`. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "inputParams": { "name": "Example", "value": "message" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'inputParams': { 'name': 'Example', 'value': 'message' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "inputParams": { "name": "Example", "value": "message" } }, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true, "outputs": { "confirmationId": "cnf_12345", "effectiveDate": "2026-08-01" } } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No action with that ID exists in your workspace. # Test attribute Source: https://docs.usefini.com/en/api-reference/test-attribute POST https://api-prod.usefini.com/v2/hc-tools/{id}/test-run/public Run the whole attribute with sample inputs. Runs the full Data Step chain for one attribute against sample inputs and returns the resolved outputs. This mirrors the dashboard Run button. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Attribute ID to run. ## Body parameters Optional sample inputs, keyed by input field name. These stand in for the runtime values the attribute would resolve at the start of a conversation. ## Response Returns an [`Action / Attribute test-run result`](/en/api-reference/actions-and-attributes#action-or-attribute-test-run-result) with per-step results and the final `extractedData`. For attributes, `attributeLlmPolicy` maps each output field to its `sendToLlm` (Visible to AI) flag. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "inputParams": { "name": "Example", "value": "message" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'inputParams': { 'name': 'Example', 'value': 'message' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/test-run/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "inputParams": { "name": "Example", "value": "message" } }, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true, "fields": { "plan": "Enterprise", "accountStatus": "active" } } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No attribute with that ID exists in your workspace. # Test external API call Source: https://docs.usefini.com/en/api-reference/test-data-step POST https://api-prod.usefini.com/v2/api-function-configs/test-run/public Test one external API call without saving. Runs a single HTTP call and returns the raw response, without persisting anything. Pass a saved step's `id` to test it as stored, or send the request fields inline to try a call before saving. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Optional saved external API call step ID. When set, the stored URL, method, headers, and body are used, with any inline fields below overriding them. Stored secrets are resolved for the call. Request URL. Required when `id` is omitted. HTTP verb. Required when `id` is omitted. Optional request headers. Optional request body. Optional values used to resolve `${fieldName}` tokens in the URL, headers, and body. ## Response Returns a [`Data Step test-run result`](/en/api-reference/actions-and-attributes#data-step-test-run-result): `success`, `statusCode`, `responseBody`, and `error` when the call failed. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/api-function-configs/test-run/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "variables": { "name": "Example", "value": "message" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/test-run/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'id': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3', 'requestUrl': 'https://help.example.com/refunds', 'requestMethod': 'GET', 'requestHeaders': { 'name': 'Example', 'value': 'message' }, 'requestBody': { 'name': 'Example', 'value': 'message' }, 'variables': { 'name': 'Example', 'value': 'message' } } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/api-function-configs/test-run/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "variables": { "name": "Example", "value": "message" } }, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true, "response": { "plan": "Enterprise", "status": "active" }, "savedFields": { "plan": "Enterprise", "status": "active" } } ``` ## Errors The body is malformed, or `requestUrl` / `requestMethod` is missing when no `id` is provided. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Update action Source: https://docs.usefini.com/en/api-reference/update-action PATCH https://api-prod.usefini.com/v2/hc-tools/{id}/public Update an action, including its input and output schema. Updates one [`Action`](/en/api-reference/actions-and-attributes#action-or-attribute-object). This is where you set the `inputSchema` and `outputSchema`. An action returns nothing to a rule unless it declares an `outputSchema`. For fields sourced from an external API call, set `source: "apiResponse"` and map each output field with `path: "[stepId].[responseMappingKey]"`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Action ID to update. ## Body parameters All fields are optional. Send only what you want to change. Updated display name. Updated description. Send `true` to convert the action into an attribute. Typed inputs. See [InputSchemaField](/en/api-reference/actions-and-attributes#inputschemafield-object). Typed outputs. See [OutputSchemaField](/en/api-reference/actions-and-attributes#outputschemafield-object). ## Response Returns the updated [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": false, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "outputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'alwaysGet': false, 'inputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ], 'outputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.patch( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": False, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "outputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Cancel subscription", "description": "Cancel an active subscription in billing.", "inputFields": [ { "name": "customerId", "type": "string", "required": true } ], "outputFields": [ { "name": "confirmationId", "type": "string" }, { "name": "effectiveDate", "type": "string" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No action with that ID exists in your workspace. Fini failed while updating the record in storage. # Update attribute Source: https://docs.usefini.com/en/api-reference/update-attribute PATCH https://api-prod.usefini.com/v2/hc-tools/{id}/public Update an attribute, including its input and output schema. Updates one [`Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). This is where you set the `inputSchema` and `outputSchema`, including the per-field `sendToLlm` ("Visible to AI") flag that controls which resolved values the agent can see. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Attribute ID to update. ## Body parameters All fields are optional. Send only what you want to change. Updated display name. Updated description. Send `false` to convert the attribute into a rule-invoked action. Typed inputs. See [InputSchemaField](/en/api-reference/actions-and-attributes#inputschemafield-object). Typed outputs. See [OutputSchemaField](/en/api-reference/actions-and-attributes#outputschemafield-object). Set `sendToLlm` per field to control "Visible to AI". For fields sourced from an external API call, set `source: "apiResponse"` and map `path` as `[stepId].[responseMappingKey]`. ## Response Returns the updated [`Action / Attribute`](/en/api-reference/actions-and-attributes#action-or-attribute-object). ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": true, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "outputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'alwaysGet': true, 'inputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ], 'outputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.patch( "https://api-prod.usefini.com/v2/hc-tools/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "alwaysGet": True, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "outputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Customer plan", "description": "Fetches the customer's active plan.", "source": "widget", "fields": [ { "name": "plan", "type": "string", "visibleToAi": true, "useInRulebooks": true } ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. No attribute with that ID exists in your workspace. Fini failed while updating the record in storage. # Update external API call Source: https://docs.usefini.com/en/api-reference/update-data-step PATCH https://api-prod.usefini.com/v2/api-function-configs/{id}/public Update one external API call step. Updates one external API call record. The wire-format object is still called [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object). All fields are optional; send only what you want to change. Sensitive header and body values are preserved when you echo the masked `"********"` back. Send a new string to replace a secret. See [Sensitive values and masking](/en/api-reference/actions-and-attributes#sensitive-values-and-masking). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters External API call step ID to update. ## Body parameters Updated step name. Updated request URL. Supports `${fieldName}` interpolation from inputs and `${stepId.responseMappingKey}` interpolation from earlier external API calls. `{{placeholder}}` syntax is not supported. Updated HTTP verb. Updated request headers. Echo the masked value back to keep a stored secret. Updated request body, with the same masking behavior as headers. Updated output mapping. See [ResponseMapping](/en/api-reference/actions-and-attributes#responsemapping-object). ## Response Returns the updated [`Data Step`](/en/api-reference/actions-and-attributes#data-step-object) with sensitive values masked. ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "responseMapping": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'requestUrl': 'https://help.example.com/refunds', 'requestMethod': 'GET', 'requestHeaders': { 'name': 'Example', 'value': 'message' }, 'requestBody': { 'name': 'Example', 'value': 'message' }, 'responseMapping': '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.patch( "https://api-prod.usefini.com/v2/api-function-configs/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "requestUrl": "https://help.example.com/refunds", "requestMethod": "GET", "requestHeaders": { "name": "Example", "value": "message" }, "requestBody": { "name": "Example", "value": "message" }, "responseMapping": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "name": "Lookup customer", "method": "GET", "url": "https://api.example.com/customers/{customerId}", "headers": { "Authorization": "Bearer ${apiToken}" }, "saveFromResponse": { "plan": "customer.plan", "status": "customer.status" }, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while updating the Data Step, for example when the ID does not exist. # Update intent rule Source: https://docs.usefini.com/en/api-reference/update-intent-rule PATCH https://api-prod.usefini.com/v2/hc-rules/{id}/public Create a new draft or published version of an intent rule. Updates intent-rule content by creating a new version. Send `status: "DRAFT"` explicitly when editing a draft. If omitted, a rule with a published version is updated by creating a new published version. A draft-only rule defaults to updating its draft. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Intent-rule ID. ## Body parameters Updated rule name. Updated routing description. Updated rule tree. Version state to update: `DRAFT` or `PUBLISHED`. `ARCHIVED` is rejected. Updated agent assignments for a published rule. Draft updates cannot include this field. ## Response Returns the updated [`Rule`](/en/api-reference/rules#rule-object). ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "status": "PUBLISHED", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'flowConfig': { 'type': 'reply', 'message': 'Escalate refund requests with order context.' }, 'status': 'PUBLISHED', 'botIds': [ '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.patch( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "status": "PUBLISHED", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "intent", "status": "PUBLISHED", "source": null, "triggerType": null, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": 3, "versionId": "v3", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed, a draft update includes `botIds`, an agent ID is invalid, or `flowConfig` references a missing action or widget form. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The intent rule does not exist in your workspace. # Update prompts Source: https://docs.usefini.com/en/api-reference/update-prompts POST https://api-prod.usefini.com/v2/bots/{id}/hc-prompt/public Save a new prompt version for one agent. Saves a new prompt version for one agent and returns the stored version. This route creates a new saved prompt version. It does not patch a prompt in place. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Agent ID whose prompts you want to update. Use [List agents](/en/api-reference/list-agents) to get the `botId`. ## Body parameters Full Planning Prompt section array. Send the complete array, not just the section you changed. Full Main Guidelines section array. Full Channel Prompt section array. For write payloads, subsection helper fields from merged reads such as `defaultPrompt` and `custom` are not required. A safe round-trip pattern is to start from [Get prompts](/en/api-reference/get-prompts), edit the arrays in place, and send them back. ## Response Returns the saved [`Prompt`](/en/api-reference/prompts#prompt-object) version. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "hcPlanningPrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcGuidelinePrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcChannelPrompt": [ "Answer only from approved knowledge and escalate if unsure." ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'hcPlanningPrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ], 'hcGuidelinePrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ], 'hcChannelPrompt': [ 'Answer only from approved knowledge and escalate if unsure.' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/bots/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/hc-prompt/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "hcPlanningPrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcGuidelinePrompt": [ "Answer only from approved knowledge and escalate if unsure." ], "hcChannelPrompt": [ "Answer only from approved knowledge and escalate if unsure." ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "9c59b2df-5d5f-4c9e-a070-9ac3c2b1b24e", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "hcPlanningPrompt": [ { "id": "planning-main", "name": "Planning", "description": "How the agent plans an answer.", "enabled": true, "custom": true, "subsections": [ { "id": "planning-grounding", "name": "Grounding", "prompt": "Use approved knowledge before answering.", "defaultPrompt": "Use retrieved knowledge before answering.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcGuidelinePrompt": [ { "id": "guidelines-main", "name": "Main Guidelines", "description": "Global answer behavior.", "enabled": true, "custom": true, "subsections": [ { "id": "guidelines-escalation", "name": "Escalation", "prompt": "Escalate billing disputes when policy is unclear.", "defaultPrompt": "Escalate when unsure.", "useDefault": false, "enabled": true, "custom": true } ] } ], "hcChannelPrompt": [ { "id": "channel-chat", "name": "Chat", "description": "Chat-specific behavior.", "enabled": true, "custom": false, "subsections": [ { "id": "channel-chat-style", "name": "Tone", "prompt": "Keep replies concise and grounded in approved knowledge.", "defaultPrompt": "Keep replies helpful and concise.", "useDefault": false, "enabled": true, "custom": true } ] } ] } ``` Current controller behavior: this response is the stored version row, not the merged template view. If you need the merged read shape with `defaultPrompt` and `custom`, call [Get prompts](/en/api-reference/get-prompts) after writing. ## Errors The body is malformed. All three top-level prompt arrays are required. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The agent ID does not exist. Current controller behavior: if the agent belongs to a different workspace, this route returns `406` with an invalid-agent message rather than `403`. Fini failed while saving the prompt version in storage. # Add feedback note Source: https://docs.usefini.com/en/api-reference/add-conversation-feedback-note POST https://api-prod.usefini.com/v2/hc-interactions/{id}/feedback-note/public Save or clear a teammate feedback note on a conversation event. Saves free-text feedback on one event, then updates the parent conversation's `hasFeedback` flag. Use this endpoint for qualitative notes that explain why a response was marked wrong or what should change. To record the thumbs-up or thumbs-down value itself, use [Send conversation feedback](/en/api-reference/send-feedback-conversation). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. Send `application/json`. ## Path parameters Conversation ID containing the event. ## Body parameters ID of the event to update. The event must belong to the conversation and workspace. Feedback note to store on the event. Send an empty string to clear the note. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/feedback-note/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "feedback": "The answer missed the 30-day refund exception." }' ``` ```python Python theme={null} import requests conversation_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.post( f"https://api-prod.usefini.com/v2/hc-interactions/{conversation_id}/feedback-note/public", headers={"Authorization": "Bearer fini_your_api_key"}, json={ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "feedback": "The answer missed the 30-day refund exception.", }, ) result = response.json() ``` ```javascript Node.js theme={null} const conversationId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/${conversationId}/feedback-note/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ eventId: "f61a9a11-2c3b-4704-8f57-7078854d87cf", feedback: "The answer missed the 30-day refund exception.", }), } ); const result = await response.json(); ``` ## Response `true` after the event feedback note and conversation feedback flag have been updated. ```json 200 OK theme={null} { "success": true } ``` ## Feedback flag When `feedback` is non-empty, Fini sets the conversation's `hasFeedback` flag to `true`. When `feedback` is empty, Fini clears this event's note and leaves `hasFeedback` true only if another event in the same conversation still has feedback. ## Errors The body fails validation. `eventId` must be a non-empty string, and `feedback`, when provided, must be a string. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The conversation or event is inaccessible, the conversation has no events, or the supplied event does not exist in the conversation. Fini could not load or update the requested conversation event. # Add criteria Source: https://docs.usefini.com/en/api-reference/add-test-set-criteria POST https://api-prod.usefini.com/v2/test-sets/{testSetId}/criteria/public Attach default or custom criteria to a test set. Adds one or more criteria to a test set. Send either a `defaultCriterionId` or a full custom criterion definition. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Test set ID. ## Body parameters One or more criteria to attach to the test set. Default criterion ID from [Get fields context](/en/api-reference/get-test-set-fields-context). When this is present, do not send custom definition fields; the API copies the default's definition. Required for custom criteria. Required for custom criteria. Use `deterministic`, `basic_judge`, or `complex_judge`. Required for `basic_judge` and `complex_judge` criteria. Required for `basic_judge` and `complex_judge` criteria. Required for `basic_judge` and `complex_judge` criteria. Required for `deterministic` criteria. Judge criteria cannot include a condition. Whether failing this criterion should fail the conversation overall. ## Response Returns the test set's updated criteria array. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/criteria/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "criteria": [ { "defaultCriterionId": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "blocking": true }, { "name": "Used a public reply", "type": "deterministic", "condition": { "scope": "ARRAY", "array": { "path": "replyTypes", "itemType": "string" }, "quantifier": "ANY", "predicate": { "left": { "path": "replyTypes", "dataType": "array" }, "operator": "contains", "right": { "value": "message" } } }, "blocking": false } ] }' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/criteria/public`, { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ criteria: [ { defaultCriterionId: '96eab02d-3bc3-4b90-ae5b-1a41a1444afa', blocking: true }, { name: 'Used a public reply', type: 'deterministic', condition: { scope: 'ARRAY', array: { path: 'replyTypes', itemType: 'string' }, quantifier: 'ANY', predicate: { left: { path: 'replyTypes', dataType: 'array' }, operator: 'contains', right: { value: 'message' } } }, blocking: false } ] }) }); const criteria = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.post( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/criteria/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "criteria": [ { "defaultCriterionId": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "blocking": True, }, { "name": "Used a public reply", "type": "deterministic", "condition": { "scope": "ARRAY", "array": { "path": "replyTypes", "itemType": "string", }, "quantifier": "ANY", "predicate": { "left": { "path": "replyTypes", "dataType": "array", }, "operator": "contains", "right": { "value": "message", }, }, }, "blocking": False, }, ], }, ) criteria = response.json() ``` ```json 201 Created theme={null} [ { "id": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "defaultCriterionId": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "name": "Goal resolution", "type": "complex_judge", "judgePrompt": "Judge whether the conversation resolved the user's goal.", "passPrompt": "The user's goal was resolved.", "failPrompt": "The user's goal was not resolved.", "condition": null, "blocking": true, "isActive": true, "createdAt": "2026-07-28T08:56:12.000Z", "updatedAt": "2026-07-28T08:56:12.000Z" }, { "id": "1e149042-74c6-446a-9da0-e48036909aa9", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "defaultCriterionId": null, "name": "Used a public reply", "type": "deterministic", "judgePrompt": null, "passPrompt": null, "failPrompt": null, "condition": { "scope": "ARRAY", "array": { "path": "replyTypes", "itemType": "string" }, "quantifier": "ANY", "predicate": { "left": { "path": "replyTypes", "dataType": "array" }, "operator": "contains", "right": { "value": "message" } } }, "blocking": false, "isActive": true, "createdAt": "2026-07-28T08:56:12.000Z", "updatedAt": "2026-07-28T08:56:12.000Z" } ] ``` # Assign knowledge to agents Source: https://docs.usefini.com/en/api-reference/assign-knowledge-to-agents POST https://api-prod.usefini.com/v2/hc-bot-folder-junctions/public Assign or unassign folders to agents in bulk. Use this route to control which folders, and therefore which knowledge, an agent can access. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Batch of folder-agent changes. Folder ID to assign or unassign. Agent ID the folder should be changed on. Action to apply. Allowed values are `ADD` and `DELETE`. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-bot-folder-junctions/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "junctions": [ { "folderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "action": "ADD" } ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-bot-folder-junctions/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'junctions': [ { 'folderId': '0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b', 'botId': '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', 'action': 'ADD' } ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-bot-folder-junctions/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "junctions": [ { "folderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "action": "ADD" } ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "folderIds": [ "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "attached": true } ``` ## Response Always `true` when the batch succeeds. ## Errors The request body is malformed, or one of the enum values is invalid. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. # Bulk delete conversations Source: https://docs.usefini.com/en/api-reference/bulk-delete-conversations DELETE https://api-prod.usefini.com/v2/hc-interactions/public Delete up to 50 conversations in one request through the public Conversations API. Use this endpoint to delete multiple conversations from the workspace tied to your API key in one request. Use [List conversations](/en/api-reference/list-conversations) to discover IDs before deleting. If you only need to delete one conversation, use [Delete conversation](/en/api-reference/delete-conversation). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ```http theme={null} DELETE /v2/hc-interactions/public Authorization: Bearer fini_xxxxxxxxxxxxxxxxx Content-Type: application/json ``` ## Body parameters Array of unique conversation IDs to delete. Provide between `1` and `50` UUIDs in one request. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-interactions/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "ids": [ "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "4d3f4c48-0467-4d7e-bbfd-2f7d02d84b5b" ] }' ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-interactions/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "ids": [ "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "4d3f4c48-0467-4d7e-bbfd-2f7d02d84b5b", ] }, ) result = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/hc-interactions/public", { method: "DELETE", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ ids: [ "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "4d3f4c48-0467-4d7e-bbfd-2f7d02d84b5b", ], }), } ); const result = await response.json(); ``` Current implementation note: bulk delete is **not atomic**. Matching conversations are removed before the route verifies that every requested ID was accessible. If any ID is missing, already removed, or belongs to a different workspace, the route returns `406 Not Acceptable`, but the matching conversations remain removed. ## Response `true` when the route completed successfully. ```json 200 OK theme={null} { "success": true } ``` ```json 406 Not Acceptable theme={null} { "statusCode": 406, "message": "One or more interactions not accessible to the user", "error": "Not Acceptable" } ``` ```json 401 Unauthorized theme={null} { "statusCode": 401, "message": "Invalid or revoked API key", "error": "Unauthorized" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ``` ## Errors The body is malformed, `ids` is missing, there are duplicate IDs, one of the IDs is not a UUID, or you sent more than `50` IDs. The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `write` scope required for these routes. One or more requested IDs were not accessible to the workspace tied to the API key. The current response message still uses the backend term `interactions`. Fini failed while updating the conversation rows in storage. # Bulk generate knowledge Source: https://docs.usefini.com/en/api-reference/bulk-generate-knowledge POST https://api-prod.usefini.com/v2/knowledge/public/bulk Queue generate-and-save jobs for multiple source IDs in one request. Use this route when you want Fini to generate knowledge directly from ingested source records at scale. This is the main self-serve route for source-backed knowledge creation and refresh. This route only supports `origin: "sources"`. It reads from the stored source content for each `documentId`, and `isDraft` defaults to `true`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Source IDs to generate from. Must be `sources` on the bulk route. Optional operation restrictions passed through to the generation pipeline. Use this to limit what Fini is allowed to do when it decides how to apply each source. Additional generation instructions. Optional agent ID to scope the generated content to. Whether the generated results should remain drafts. ## `restrictedOps` values Use `restrictedOps` to limit the operation choices available to the knowledge-generation pipeline for every source in the batch. | Value | Meaning | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `ADD_ARTICLE_TO_FOLDER` | Allow Fini to create a new article in an existing folder. | | `UPDATE_ARTICLE` | Allow Fini to update an existing article that the pipeline selects as the best match. | | `DO_NOTHING` | Allow Fini to decide that no knowledge change should be applied. When `isDraft` is `true`, this still creates a reviewable draft/no-op record. | ## Response One queued job per input source. Input source ID. Queued background job ID for that source. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/knowledge/public/bulk' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "documentIds": [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "35b4838a-4136-4f6c-a530-8f17cb47566d" ], "origin": "sources", "isDraft": true }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/knowledge/public/bulk", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "documentIds": [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "35b4838a-4136-4f6c-a530-8f17cb47566d", ], "origin": "sources", "isDraft": True, }, ) jobs = response.json() ``` ```javascript Node.js theme={null} const response = await fetch("https://api-prod.usefini.com/v2/knowledge/public/bulk", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ documentIds: [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "35b4838a-4136-4f6c-a530-8f17cb47566d", ], origin: "sources", isDraft: true, }), }); const jobs = await response.json(); ``` ```json 200 OK theme={null} { "jobs": [ { "documentId": "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "backgroundJobId": "4cfcf2cc-7a06-4de2-b460-5b991fe6236a" }, { "documentId": "35b4838a-4136-4f6c-a530-8f17cb47566d", "backgroundJobId": "1b18f1d5-f5cc-4fc2-8d5b-38d4a7c5f28b" } ] } ``` ## Refresh existing knowledge from changed sources If existing sources already back knowledge in Fini and the upstream content changes, the refresh sequence is: Call [Refresh sources](/en/api-reference/refresh-sources) with the source IDs you already have. Use [List sources](/en/api-reference/list-sources) or [Get source](/en/api-reference/get-source) until `linkedJobStatus` moves to `COMPLETED`. Call [List sources](/en/api-reference/list-sources) with `changed=true`. If you only want web content, also pass `source=web`. Keep the source records that already have a `linkedKnowledgeId`. Call this route with the changed `documentIds`. Use `isDraft: true` if you want to review the updates first. Use `isDraft: false` only if you want the updated knowledge saved live immediately. Call [Check knowledge jobs](/en/api-reference/check-knowledge-jobs) with the returned job IDs until the jobs finish. If you created drafts, review and publish them before expecting live answers to change. After a successful source-backed save, Fini syncs the source's linked knowledge reference and clears the `changed` flag on that source record. ## Errors The request body is malformed, `documentIds` is missing or empty, or `origin` is not `sources`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. Fini failed while queueing or processing one or more generation jobs. Retry once, then inspect the job IDs with [Check knowledge jobs](/en/api-reference/check-knowledge-jobs). # Check knowledge jobs Source: https://docs.usefini.com/en/api-reference/check-knowledge-jobs POST https://api-prod.usefini.com/v2/knowledge/public/jobs/status Check status for one or more background knowledge-generation jobs. Use this route to poll background jobs queued by [Generate knowledge](/en/api-reference/generate-knowledge) or [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. `application/json` ## Body parameters Background job IDs to inspect. ## Response Status rows for the requested jobs. Background job ID. Current job status. ISO 8601 creation timestamp, when present. ISO 8601 start timestamp, when present. ISO 8601 completion timestamp, when present. Linked Article ID once the job finishes and creates or updates knowledge. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/knowledge/public/jobs/status' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "jobIds": [ "4cfcf2cc-7a06-4de2-b460-5b991fe6236a" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/knowledge/public/jobs/status', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'jobIds': [ 'job_01j4fq3f0p7mef4p2j2h2vp4my' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/knowledge/public/jobs/status", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "jobIds": [ "job_01j4fq3f0p7mef4p2j2h2vp4my" ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "jobs": [ { "id": "4cfcf2cc-7a06-4de2-b460-5b991fe6236a", "jobStatus": "COMPLETED", "createdAt": "2026-06-11T12:00:00.000Z", "startedAt": "2026-06-11T12:00:01.000Z", "completedAt": "2026-06-11T12:00:05.000Z", "hcArticleId": "7f5392e5-dc7d-4558-8860-cf3ea4b32f94" } ] } ``` ## Errors The request body is malformed or `jobIds` is missing or empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope. One or more job IDs do not exist, are inaccessible from this workspace, or are not knowledge-generation jobs. Fini failed while reading job status. Retry once, then narrow the request to isolate the failing job ID. # Overview Source: https://docs.usefini.com/en/api-reference/conversations List conversations, fetch a conversation, send message events, record event feedback, evaluate rules, and delete conversations through Fini's public API. Conversations are the customer interaction records behind Inbox, testing, feedback, and answer-generation workflows. Use these routes to export conversation data, send a new message event, record thumbs-up or thumbs-down feedback on an event, evaluate a rule against an existing conversation, or delete conversations. The wire-format paths use `/hc-interactions` because that is the current backend contract. In this reference, we call them **conversations** to match the product surface. ## Reference pages `GET /v2/hc-interactions/public` - export conversations with filters and cursor pagination. `GET /v2/hc-interactions/{id}/public` - fetch one conversation by ID. `GET /v2/hc-events/{id}/metadata` - fetch the trace metadata for one Fini-authored event. `POST /v2/hc-interactions/events/public` - add a message event and generate the next Fini response. `POST /v2/hc-interactions/{id}/feedback/public` - set or clear an event feedback value. `POST /v2/hc-interactions/{id}/feedback-resolved/public` - mark a negatively rated event resolved or unresolved. `POST /v2/hc-interactions/{id}/feedback-note/public` - save a teammate feedback note on an event. `POST /v2/hc-interactions/{id}/evaluate-rule/{ruleId}/public` - run one rule against an existing conversation. `DELETE /v2/hc-interactions/{id}/public` - delete one conversation. `DELETE /v2/hc-interactions/public` - delete up to 50 conversations by ID. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | ------------------------------------------------------ | ------- | -------------------------------------------------------- | | `GET` | `/v2/hc-interactions/public` | `read` | Export conversations with filters and cursor pagination. | | `GET` | `/v2/hc-interactions/:id/public` | `read` | Fetch one conversation by ID. | | `GET` | `/v2/hc-events/:id/metadata` | `read` | Fetch trace metadata for one Fini-authored event. | | `POST` | `/v2/hc-interactions/events/public` | `write` | Add a message event and generate the next Fini response. | | `POST` | `/v2/hc-interactions/:id/feedback/public` | `write` | Set or clear an event feedback value. | | `POST` | `/v2/hc-interactions/:id/feedback-resolved/public` | `write` | Mark a negatively rated event resolved or unresolved. | | `POST` | `/v2/hc-interactions/:id/feedback-note/public` | `write` | Save or clear a teammate feedback note on an event. | | `POST` | `/v2/hc-interactions/:id/evaluate-rule/:ruleId/public` | `write` | Evaluate one rule against an existing conversation. | | `DELETE` | `/v2/hc-interactions/:id/public` | `write` | Delete one conversation. | | `DELETE` | `/v2/hc-interactions/public` | `write` | Delete up to 50 conversations. | # Create article Source: https://docs.usefini.com/en/api-reference/create-article POST https://api-prod.usefini.com/v2/hc-articles/public Create a live article or draft article directly in the workspace. Use this route when you want to write articles directly instead of generating them from sources. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Article title. Main knowledge body. Instructions the agent should apply when using this article. Related questions for the article. Keywords for the article. Whether the article is escalation-related. Folder that should contain the article. Whether to create the article as a draft instead of a live article. Optional origin marker to store with the article. `POST /v2/hc-articles/public` only uses the fields documented above. Even though the internal DTO also permits `active`, `public`, and `originalArticleId`, the public create controller does not pass them through. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "title": "Canceling your subscription", "mainKnowledge": "Customers can cancel from Billing in the dashboard.", "agentInstruction": "Use this only for self-serve web plans.", "questions": ["How do I cancel?", "Can I end my plan today?"], "keywords": ["cancel", "subscription", "billing"], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'title': 'Refund policy', 'mainKnowledge': 'Customers can request a refund within 30 days of purchase.', 'agentInstruction': '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', 'questions': [ 'How do refunds work?' ], 'keywords': [ 'refund' ], 'escalation': true, 'parentFolderId': '0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b', 'isDraft': false, 'origin': 'api' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "questions": [ "How do refunds work?" ], "keywords": [ "refund" ], "escalation": True, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": False, "origin": "api" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Response Returns the created article object. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. Because the public create route does not expose `active` or `public`, newly created articles currently come back with the service defaults for those fields. ## Errors The request body is malformed or one of the required arrays is empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. # Create article draft Source: https://docs.usefini.com/en/api-reference/create-article-draft POST https://api-prod.usefini.com/v2/hc-articles/{id}/draft/public Create a draft from an existing live article. Use this route to fork an existing live article into a draft for review. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Original live article ID to fork from. ## Body parameters This route uses the same required content fields as [Create article](/en/api-reference/create-article). `active`, `public`, and `origin` are also accepted here. ## Response Returns the created draft article object. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/draft/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/draft/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/draft/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` For drafts created from an existing live article, the response typically includes `originalArticleId`, `originalArticleVersion`, and `isDraftPublished: false`. If the source live article does not exist, the current route returns `null` instead of a `404`. ## Errors The request body is malformed or one of the required arrays is empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. # Create Business Rule Source: https://docs.usefini.com/en/api-reference/create-business-rule POST https://api-prod.usefini.com/v2/hc-rules/public Create a custom or template-based Business Rule. Creates a Business Rule. Business Rules are stored directly and do not have a draft lifecycle. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Rule name. Description of the escalation workflow. Send `business`. Business Rule source. The current enum value is `widget`. Business Rule trigger. The current enum value is `on_escalation`. Required for a custom Business Rule. Do not send it for a template-based rule. Template ID from [List default Business Rules](/en/api-reference/list-default-rules). A template-based rule cannot also define `flowConfig`. Runtime bindings for Business Rule inputs, including template inputs. Agent IDs to assign after creation. ## Response Returns the created [`Rule`](/en/api-reference/rules#rule-object). ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-rules/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "type": "business", "source": "widget", "triggerType": "on_escalation", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "defaultRuleId": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'type': 'business', 'source': 'widget', 'triggerType': 'on_escalation', 'flowConfig': { 'type': 'reply', 'message': 'Escalate refund requests with order context.' }, 'defaultRuleId': 'b8b8d87b-2f0c-47f6-8a8a-546da73e0820', 'inputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ], 'botIds': [ '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-rules/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "type": "business", "source": "widget", "triggerType": "on_escalation", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "defaultRuleId": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed, a custom rule has no `flowConfig`, a template is invalid, a template-based rule also defines `flowConfig`, or a referenced agent, action, or widget form is invalid. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. # Create Refine with AI iteration Source: https://docs.usefini.com/en/api-reference/create-fix-review-iteration POST https://api-prod.usefini.com/v2/fix-review/interactions/{id}/events/{eventId}/sessions/iterations/public Queue an AI-assisted refinement analysis for one Fini response. Starts a Refine with AI iteration for one Fini response. Fini creates or reuses the response's active review session, queues asynchronous analysis and replay, and immediately returns identifiers you can use to poll the session. This endpoint needs `write` scope. Creating an iteration generates recommendations and a replay, but does not publish or apply the suggested changes. Use this endpoint when you already know the conversation ID and Fini response event ID to review. Use [List conversations](/en/api-reference/list-conversations) or [Get conversation](/en/api-reference/get-conversation) to discover event IDs before queueing a review. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. Send `application/json`. ## Path parameters Conversation ID containing the response to review. ID of the Fini response to review. The event must belong to the conversation and have a linked user event so Fini can replay it. ## Body parameters Description of what was wrong with the response or how it should improve. Must be non-empty and at most 2,000 characters. ## Request example ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/fix-review/interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/events/f61a9a11-2c3b-4704-8f57-7078854d87cf/sessions/iterations/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "feedbackNote": "The answer should explain the cancellation deadline before linking to Billing Settings." }' ``` ```python Python theme={null} import requests interaction_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" event_id = "f61a9a11-2c3b-4704-8f57-7078854d87cf" response = requests.post( f"https://api-prod.usefini.com/v2/fix-review/interactions/{interaction_id}/events/{event_id}/sessions/iterations/public", headers={"Authorization": "Bearer fini_your_api_key"}, json={ "feedbackNote": "The answer should explain the cancellation deadline before linking to Billing Settings." }, ) job = response.json() ``` ```javascript Node.js theme={null} const interactionId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const eventId = "f61a9a11-2c3b-4704-8f57-7078854d87cf"; const response = await fetch( `https://api-prod.usefini.com/v2/fix-review/interactions/${interactionId}/events/${eventId}/sessions/iterations/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ feedbackNote: "The answer should explain the cancellation deadline before linking to Billing Settings.", }), } ); const job = await response.json(); ``` ## Response Active Refine with AI session ID. A later iteration for the same response can reuse this session while it remains active. ID of the newly queued iteration. ID of the background job processing the iteration. ```json 200 OK theme={null} { "sessionId": "91d2d432-b408-4496-920d-24ad6a1b9e87", "iterationId": "55ce8421-3da6-49f7-af02-b0f23458437d", "backgroundJobId": "641482a8-a952-42d2-bceb-67ca06b79e92" } ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": "A fix iteration is already running for this response", "error": "Bad Request" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ``` ## Polling the result The response only confirms that processing was queued. Poll [Get Refine with AI session](/en/api-reference/get-fix-review-session) with the returned `sessionId`, or call [Get active Refine with AI session](/en/api-reference/get-active-fix-review-session) for the selected response. An iteration progresses through `queued`, `generating_changes`, and `replaying`. A terminal result is `ready`, `no_change`, or `failed`. Older ready iterations can become `superseded`, and applied iterations use `published`. When the session returns a `ready` `latestIteration`, use `oldAnswerSnapshot` and `newAnswerSnapshot` to compare the original response with the replayed response. Use `changes` to find the proposed prompt, knowledge, or rule drafts. The create response does not contain those results because the work runs asynchronously. For the dashboard workflow and review model, see [Refine with AI](/en/testing/fix-with-ai). ## Errors The feedback is empty or longer than 2,000 characters, an iteration is already in progress, the event does not belong to the conversation, the event is not Fini-authored, or it has no linked user event for replay. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The conversation or target event does not exist in the workspace. Fini could not create or queue the Refine with AI iteration. # Create knowledge folder Source: https://docs.usefini.com/en/api-reference/create-knowledge-folder POST https://api-prod.usefini.com/v2/hc-folders/public Create a folder in the knowledge tree. Use this route to add a new folder to the knowledge tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Folder title. Folder description. Can be an empty string. Parent folder ID for nesting. Omit for a top-level folder. ## Response Returns the created knowledge folder object. See [Organize knowledge](/en/api-reference/organize-knowledge) for the shared folder fields. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-folders/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "title": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-folders/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'title': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'parentFolderId': '0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-folders/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "title": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The request body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The parent folder does not exist, or you attempted a structure change the tree does not allow. # Create replay Source: https://docs.usefini.com/en/api-reference/create-replay POST https://api-prod.usefini.com/v2/replays/public Run an existing conversation turn against the current agent configuration. Creates a replay conversation from an existing conversation and target Fini response event. The replay runs immediately, stores its result as a separate conversation, and returns the replay conversation. This endpoint needs `write` scope. It creates a replay record, but it does not change the original conversation or publish any configuration changes. Use [List conversations](/en/api-reference/list-conversations) or [Get conversation](/en/api-reference/get-conversation) to find the original conversation ID and the Fini response event ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. Send `application/json`. ## Body parameters ID of the original conversation to replay. ID of the Fini response event to replay. The response must have a linked user event in the same conversation. Replay mode. Use `until` to replay up to the selected response, or `single` to replay only that response. Defaults to `until`. Optional model overrides for this replay run. Supported keys are `performPlanning`, `searchKnowledge`, `generateAnswer`, and `tagSelection`; each value must be a non-empty model name. Optional answer-generation artifacts to inject into the replay. Use this only when you have validated artifact data from Fini's conversation tooling. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/replays/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "interactionId": "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "mode": "until", "mlModels": { "generateAnswer": "gpt-4.1" } }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/replays/public", headers={"Authorization": "Bearer fini_your_api_key"}, json={ "interactionId": "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "mode": "until", "mlModels": {"generateAnswer": "gpt-4.1"}, }, ) replay = response.json() ``` ```javascript Node.js theme={null} const response = await fetch("https://api-prod.usefini.com/v2/replays/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ interactionId: "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", eventId: "f61a9a11-2c3b-4704-8f57-7078854d87cf", mode: "until", mlModels: { generateAnswer: "gpt-4.1" }, }), }); const replay = await response.json(); ``` ## Response Returns the replay conversation record. Replay conversation ID. Original conversation ID this replay was created from. Replay metadata, including `target_event_id`, `status`, and optional `ml_models`. ```json 200 OK theme={null} { "id": "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625", "companyId": "6bc9f4f8-3564-4a9c-8cc0-ea1f1dd66c2d", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "source": "replay", "channel": "widget", "status": "resolved", "createdAt": "2026-07-30T12:18:03.211Z", "updatedAt": "2026-07-30T12:18:14.904Z", "parentInteractionId": "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "replay": { "target_event_id": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "status": "done", "ml_models": { "generateAnswer": "gpt-4.1" } } } ``` ## Errors The body failed validation. `interactionId` and `eventId` must be UUIDs, `mode` must be `until` or `single`, and `mlModels` can only include supported operation keys with non-empty string values. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The target event does not exist in the workspace, or the event does not belong to the supplied conversation. The target event is not a Fini response, the response has no linked user event to replay, or the replay run failed. # Create tag Source: https://docs.usefini.com/en/api-reference/create-tag POST https://api-prod.usefini.com/v2/tag-groups/{id}/tags/public Create a tag inside one tag group. Creates a [`Tag`](/en/api-reference/tags#tag-object) inside one tag group. Supported contract: create tags inside workspace-owned custom groups. For group-level routes, see [Tag groups](/en/api-reference/tag-groups). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Tag group ID that should own the new tag. ## Body parameters Tag label. Optional tag description or instruction text. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/tag-groups/f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5/tags/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "tagName": "resolved_by_ai", "tagDescription": "Use when the assistant fully resolved the request." }' ``` ```python Python theme={null} import requests tag_group_id = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5" response = requests.post( f"https://api-prod.usefini.com/v2/tag-groups/{tag_group_id}/tags/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "tagName": "resolved_by_ai", "tagDescription": "Use when the assistant fully resolved the request.", }, ) tag = response.json() ``` ```javascript Node.js theme={null} const tagGroupId = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/${tagGroupId}/tags/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ tagName: "resolved_by_ai", tagDescription: "Use when the assistant fully resolved the request.", }), } ); const tag = await response.json(); ``` ## Response Returns the created [`Tag`](/en/api-reference/tags#tag-object). ```json 201 Created theme={null} { "id": "0dc53764-a417-4a4f-b7f4-63149529f530", "createdAt": "2026-06-19T07:32:10.000Z", "tagGroupId": "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5", "tagName": "resolved_by_ai", "tagDescription": "Use when the assistant fully resolved the request." } ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": [ "tagName should not be empty" ], "error": "Bad Request" } ``` Current controller behavior: unknown tag group IDs currently surface as `500 Internal Server Error` on this public route. ## Errors The body is malformed or missing the required `tagName`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while loading the group or creating the tag. # Create tag group Source: https://docs.usefini.com/en/api-reference/create-tag-group POST https://api-prod.usefini.com/v2/tag-groups/public Create a custom tag group. Creates a custom tag group and returns the stored [`TagGroup`](/en/api-reference/tag-groups#taggroup-object). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Group title. Optional group description. Optional AI-instruction text for the group's tag selection logic. Optional flag controlling whether the group allows multiple tags per conversation. Optional flag for output-only groups. If `true`, this group will not be available in Rulebooks, including intent-based rules, so leave it `false` for routing or other Rulebook conditions. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/tag-groups/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "title": "Resolution Outcome", "description": "Post-reply outcome tags for downstream workflows.", "prompt": "Apply the tag that best describes how the assistant handled the conversation.", "multiselect": false, "isOutputTagGroup": true }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/tag-groups/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "title": "Resolution Outcome", "description": "Post-reply outcome tags for downstream workflows.", "prompt": "Apply the tag that best describes how the assistant handled the conversation.", "multiselect": False, "isOutputTagGroup": True, }, ) tag_group = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/tag-groups/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ title: "Resolution Outcome", description: "Post-reply outcome tags for downstream workflows.", prompt: "Apply the tag that best describes how the assistant handled the conversation.", multiselect: false, isOutputTagGroup: true, }), } ); const tagGroup = await response.json(); ``` ## Response Returns the created [`TagGroup`](/en/api-reference/tag-groups#taggroup-object). ```json 201 Created theme={null} { "id": "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5", "createdAt": "2026-06-19T07:30:11.000Z", "companyId": "38ba4db0-31db-4669-bb95-7b8313c4016b", "title": "Resolution Outcome", "description": "Post-reply outcome tags for downstream workflows.", "prompt": "Apply the tag that best describes how the assistant handled the conversation.", "multiselect": false, "updatedAt": "2026-06-19T07:30:11.000Z", "mandatory": false, "isOutputTagGroup": true } ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": [ "title should not be empty" ], "error": "Bad Request" } ``` ## Errors The body is malformed or missing the required `title`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while creating the tag group in storage. # Create a test set Source: https://docs.usefini.com/en/api-reference/create-test-set POST https://api-prod.usefini.com/v2/test-sets/public Create a Test Suite regression set from existing conversation IDs. Creates a test set from existing conversation IDs. Add criteria separately before starting a run. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Non-empty test set name. Optional description. One to 200 existing conversation IDs. Each value must be a UUID. ## Response Returns the created [TestSet object](/en/api-reference/test-sets#testset-object). New test sets return an empty `criteria` array until you attach criteria with [Add criteria](/en/api-reference/add-test-set-criteria). ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/test-sets/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund regression set", "description": "Refund-policy conversations to re-check before prompt changes.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/test-sets/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Refund regression set', description: 'Refund-policy conversations to re-check before prompt changes.', conversationIds: [ 'a5221094-72d4-4b9c-8d30-2f785b108bd9', '2dd2b920-f57c-4e92-8a6a-f310d4c8594d' ] }) }); const testSet = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/test-sets/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "name": "Refund regression set", "description": "Refund-policy conversations to re-check before prompt changes.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d", ], }, ) test_set = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "status": "success", "createdAt": "2026-07-28T08:55:32.000Z" } ``` # Crawl links Source: https://docs.usefini.com/en/api-reference/deep-crawl-links POST https://api-prod.usefini.com/v2/documents/public/deep-crawl/links Discover additional web URLs from one or more seed links before ingesting them as sources. Use this route when you have one or a few seed URLs and want Fini to discover more web pages before you call [Ingest sources](/en/api-reference/ingest-sources). This route discovers URLs only. It does not create source records and it does not ingest content. After you pick the URLs you want, send them to [Ingest sources](/en/api-reference/ingest-sources) with `source: "web"`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Seed URLs to crawl. Maximum number of discovered URLs to return. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/documents/public/deep-crawl/links' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "links": ["https://help.example.com"], "limit": 50 }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/documents/public/deep-crawl/links", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "links": ["https://help.example.com"], "limit": 50, }, ) data = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/documents/public/deep-crawl/links", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ links: ["https://help.example.com"], limit: 50, }), } ); const data = await response.json(); ``` ## Response Discovered child URLs. Success message. ```json 200 OK theme={null} { "data": [ "https://help.example.com/articles/returns", "https://help.example.com/articles/shipping" ], "message": "Successfully crawled parent URLs" } ``` ## Next step Take the URLs you want from `data`, then call [Ingest sources](/en/api-reference/ingest-sources) with `source: "web"` and place those URLs into `documentIdsToAdd`. ## Errors The request body is malformed, `links` is missing or empty, or one of the inputs is not a valid URL. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. Fini failed while crawling one or more seed URLs. Retry once, then narrow the input set to isolate the failing URL. # Delete article Source: https://docs.usefini.com/en/api-reference/delete-article DELETE https://api-prod.usefini.com/v2/hc-articles/{id}/public Delete an article. Use this route to remove a live article or draft article from your workspace. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Article ID to delete. ## Response Returns the deleted article object. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The article does not exist in the workspace. # Delete Business Rule Source: https://docs.usefini.com/en/api-reference/delete-business-rule DELETE https://api-prod.usefini.com/v2/hc-rules/{id}/public Delete a Business Rule and its agent assignments. Deletes a Business Rule and removes its agent assignments. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Business Rule ID to delete. ## Response Returns `204 No Content` when the delete succeeds. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The Business Rule does not exist in your workspace. # Delete conversation Source: https://docs.usefini.com/en/api-reference/delete-conversation DELETE https://api-prod.usefini.com/v2/hc-interactions/{id}/public Delete one conversation by ID through the public Conversations API. Use this endpoint to delete one conversation from the workspace tied to your API key. Use [List conversations](/en/api-reference/list-conversations) to discover IDs before deleting. If you need to remove multiple conversations in one request, use [Bulk delete conversations](/en/api-reference/bulk-delete-conversations). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Conversation ID to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests conversation_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.delete( f"https://api-prod.usefini.com/v2/hc-interactions/{conversation_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```javascript Node.js theme={null} const conversationId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/${conversationId}/public`, { method: "DELETE", headers: { Authorization: "Bearer fini_your_api_key", }, } ); const result = await response.json(); ``` Current implementation note: this route returns `{ "success": true }` once the update query completes. It does not currently verify that the ID matched a live conversation, so missing, already-removed, or workspace-mismatched IDs can still return success. ## Response `true` when the route completed successfully. ```json 200 OK theme={null} { "success": true } ``` ```json 401 Unauthorized theme={null} { "statusCode": 401, "message": "Invalid or revoked API key", "error": "Unauthorized" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `write` scope required for this route. Fini failed while updating the conversation row in storage. # Delete knowledge folder Source: https://docs.usefini.com/en/api-reference/delete-knowledge-folder DELETE https://api-prod.usefini.com/v2/hc-folders/{id}/public Delete a folder from the knowledge tree. Use this route to remove a folder from the tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Folder ID to delete. ## Response Returns the deleted knowledge folder object. See [Organize knowledge](/en/api-reference/organize-knowledge) for the shared folder fields. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The folder does not exist in the workspace. # Delete sources Source: https://docs.usefini.com/en/api-reference/delete-sources DELETE https://api-prod.usefini.com/v2/documents/public Delete source records and optionally delete the linked Articles in the same request. Use this route to remove source records that no longer belong in the workspace. Deleting a source removes the input record. It only deletes linked Articles if you explicitly set `deleteArticles` to `true`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Source IDs to delete. Whether linked articles should be deleted too. ## Response Deleted source records. Articles deleted because `deleteArticles` was `true`. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/documents/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "documentIds": ["5d9f67a8-d853-4af4-b7ce-23ebba1245e5"], "deleteArticles": true }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/documents/public', { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'documentIds': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ], 'deleteArticles': true } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.delete( "https://api-prod.usefini.com/v2/documents/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "documentIds": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "deleteArticles": True }, ) data = response.json() ``` ```json 200 OK theme={null} { "deletedDocuments": [ { "id": "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "title": "Refund policy", "originalUrl": "https://help.example.com/refunds" } ], "deletedArticles": [ { "id": "7f5392e5-dc7d-4558-8860-cf3ea4b32f94", "title": "Refund policy", "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" } ] } ``` ## Errors The request body is malformed, `documentIds` is missing or empty, or one of the source IDs does not exist. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope, or the source IDs belong to a different workspace. Fini failed while deleting one or more records. Retry once, then inspect the affected IDs in [List sources](/en/api-reference/list-sources). # Delete tag Source: https://docs.usefini.com/en/api-reference/delete-tag DELETE https://api-prod.usefini.com/v2/tag-groups/tags/{id}/public Delete one tag by tag ID. Deletes one tag. The `{id}` path segment is the tag ID on this route, not the tag group ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Tag ID to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/tag-groups/tags/0dc53764-a417-4a4f-b7f4-63149529f530/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests tag_id = "0dc53764-a417-4a4f-b7f4-63149529f530" response = requests.delete( f"https://api-prod.usefini.com/v2/tag-groups/tags/{tag_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```javascript Node.js theme={null} const tagId = "0dc53764-a417-4a4f-b7f4-63149529f530"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/tags/${tagId}/public`, { method: "DELETE", headers: { Authorization: "Bearer fini_your_api_key", }, } ); const result = await response.json(); ``` ## Response `true` when the delete completed successfully. ```json 200 OK theme={null} { "success": true } ``` Current controller behavior: unknown tag IDs currently surface as `500 Internal Server Error` on this route. Tags in Fini-managed groups are also not part of the supported write contract. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while resolving the tag or deleting it from storage. # Delete tag group Source: https://docs.usefini.com/en/api-reference/delete-tag-group DELETE https://api-prod.usefini.com/v2/tag-groups/{id}/public Delete a custom tag group. Deletes a custom tag group. Use this route only for workspace-owned custom groups you created. Tag-level routes live on [Tags](/en/api-reference/tags). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Tag group ID to delete. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/tag-groups/f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests tag_group_id = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5" response = requests.delete( f"https://api-prod.usefini.com/v2/tag-groups/{tag_group_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```javascript Node.js theme={null} const tagGroupId = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/${tagGroupId}/public`, { method: "DELETE", headers: { Authorization: "Bearer fini_your_api_key", }, } ); const result = await response.json(); ``` ## Response `true` when the delete completed successfully. ```json 200 OK theme={null} { "success": true } ``` Current controller behavior: unknown IDs and attempts to delete mandatory groups currently surface as `500 Internal Server Error` on this public route. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while deleting the tag group. Unknown or non-deletable IDs currently surface here as well. # Delete a test set Source: https://docs.usefini.com/en/api-reference/delete-test-set DELETE https://api-prod.usefini.com/v2/test-sets/{testSetId}/public Delete a Test Suite regression set. Deletes a test set. Deletion fails while the test set has an active run. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Test set ID. ## Response Returns `{ "success": true }`. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/public`, { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const result = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.delete( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` # Delete a criterion Source: https://docs.usefini.com/en/api-reference/delete-test-set-criterion DELETE https://api-prod.usefini.com/v2/test-sets/{testSetId}/criteria/{criteriaId}/public Delete one criterion from a test set. Deletes one criterion from a test set. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Test set ID. Criterion ID. ## Response Returns `{ "success": true }`. ```bash cURL theme={null} curl --request DELETE \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/criteria/96eab02d-3bc3-4b90-ae5b-1a41a1444afa/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const criteriaId = '96eab02d-3bc3-4b90-ae5b-1a41a1444afa'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/criteria/${criteriaId}/public`, { method: 'DELETE', headers: { Authorization: 'Bearer fini_your_api_key' } }); const result = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" criteria_id = "96eab02d-3bc3-4b90-ae5b-1a41a1444afa" response = requests.delete( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/criteria/{criteria_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) result = response.json() ``` ```json 200 OK theme={null} { "success": true } ``` # Evaluate conversation rule Source: https://docs.usefini.com/en/api-reference/evaluate-conversation-rule POST https://api-prod.usefini.com/v2/hc-interactions/{id}/evaluate-rule/{ruleId}/public Run one rule against an existing conversation and return the evaluated rule-node results. Evaluates a rule against the context already stored on one conversation. Use this when you want to debug or preview how a rule resolves for a real conversation record without constructing the input context yourself. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Conversation ID. Rule ID to evaluate. ## Response Returns an array of rule-node evaluation results. Each item describes how a node resolved while the rule was evaluated against the conversation. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-interactions/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate-rule/b8b8d87b-2f0c-47f6-8a8a-546da73e0820/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-interactions/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate-rule/b8b8d87b-2f0c-47f6-8a8a-546da73e0820/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-interactions/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/evaluate-rule/b8b8d87b-2f0c-47f6-8a8a-546da73e0820/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "status": "resolved", "source": "widget", "user": { "name": "Sam Lee", "email": "customer@example.com" }, "messages": [ { "role": "user", "content": "How do refunds work?", "createdAt": "2026-07-28T08:55:32.000Z" }, { "role": "assistant", "content": "Refunds are available within 30 days.", "createdAt": "2026-07-28T08:55:40.000Z" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` This is a diagnostic execution route. It evaluates the rule and returns node results; it does not send a reply to the customer. # Generate Answer Source: https://docs.usefini.com/en/api-reference/generate-answer POST https://api-prod.usefini.com/v2/hc-interactions/events/public Send a message event into Fini and return the public events created for that submission. Use this endpoint when your backend needs to send a turn into Fini. Pass `interactionId` to continue an existing conversation, or `botId` to let Fini create or resolve one for that agent. The route stores the incoming event, runs the normal reply flow for `user` messages, and returns the public event objects created while handling that submission. Use [List agents](/en/api-reference/list-agents) to get a `botId`. This route returns only the created event array, not the full conversation wrapper. Use [Get conversation](/en/api-reference/get-conversation) when you already know the conversation ID, or [List conversations](/en/api-reference/list-conversations) when you need to discover or export it. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Body parameters Message text to add as the incoming event. Event role. Allowed values are `user`, `agent`, `finibot`, and `otherbot`. Most public callers should use `user`. Existing conversation ID to continue. If omitted, provide `botId` and Fini will create or resolve a conversation for that bot. Agent ID to use when starting a new conversation. Required when `interactionId` is omitted. Optional conversation metadata to merge into the request state. User attributes to merge into the conversation metadata for this submission. Optional channel override. Allowed values are `chat` and `email`. Optional generation artifacts to use for this answer. Use this when you want Fini to answer with a specific prompt draft, knowledge snapshot, article drafts, or rule versions. Prompt version ID to use for answer generation. Knowledge snapshot ID to use for retrieval. Knowledge article draft IDs to include in retrieval. Rule version IDs to use while evaluating the reply flow. Public file attachments are not accepted by `Generate Answer`. Use `artifacts` for prompt, knowledge, and rule-version inputs that affect answer generation. ## Request example ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-interactions/events/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "role": "user", "content": "Where is my order?", "metadata": { "user_attributes": { "email": "customer@example.com" }, "channel": "chat" }, "artifacts": { "promptVersionId": "11111111-1111-4111-8111-111111111111", "knowledgeSnapshotId": "22222222-2222-4222-8222-222222222222", "knowledgeArticleDraftIds": [ "33333333-3333-4333-8333-333333333333" ], "ruleVersionIds": [ "44444444-4444-4444-8444-444444444444" ] } }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-interactions/events/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "role": "user", "content": "Where is my order?", "metadata": { "user_attributes": {"email": "customer@example.com"}, "channel": "chat", }, "artifacts": { "promptVersionId": "11111111-1111-4111-8111-111111111111", "knowledgeSnapshotId": "22222222-2222-4222-8222-222222222222", "knowledgeArticleDraftIds": [ "33333333-3333-4333-8333-333333333333" ], "ruleVersionIds": [ "44444444-4444-4444-8444-444444444444" ], }, }, ) events = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/hc-interactions/events/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ botId: "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", role: "user", content: "Where is my order?", metadata: { user_attributes: { email: "customer@example.com" }, channel: "chat", }, artifacts: { promptVersionId: "11111111-1111-4111-8111-111111111111", knowledgeSnapshotId: "22222222-2222-4222-8222-222222222222", knowledgeArticleDraftIds: [ "33333333-3333-4333-8333-333333333333", ], ruleVersionIds: [ "44444444-4444-4444-8444-444444444444", ], }, }), } ); const events = await response.json(); ``` If you send `role: "agent"` or another non-user role, Fini stores that event and returns it immediately. The route only generates a new AI reply for `user` events. ## Response The response is a top-level array of public events created while handling this submission. This is the same event shape returned inside `events[]` on [List conversations](/en/api-reference/list-conversations). The request body sends incoming text as `content`. Public event responses expose stored event text as `message`, including both the user event created from your `content` and any Fini reply generated for that turn. Array of public events created for the submission. Event ID. ID of the conversation the event belongs to. Pass it as `interactionId` on the next request to continue the same conversation. Event creation time in Unix epoch milliseconds. Event role such as `user`, `finibot`, `agent`, or `otherbot`. Event type such as `message`, `internalnote`, `no_reply`, `silent_escalation`, `debounce`, or `widget_form`. Message content stored on the event, when present. This is the response-side field name for event text; the request body field is `content`. Provider-side message ID when available. Provider-side timestamp in Unix epoch milliseconds when available. Numeric CSAT value attached to the event, when present. Free-text feedback note stored on the event, when present. Thumbs up (`true`), thumbs down (`false`), or unrated (`null`). Resolution flag stored on the event, when present. File attachments on the event. When present, signed attachment URLs are refreshed before the response is returned. Current signed URL for downloading the attachment. Internal storage path for the attachment. Original source URL recorded for the attachment. MIME type of the attachment. Unix epoch milliseconds when the signed download URL expires. File size in bytes when available. Tags attached to the event. Tag ID. Tag name. Parent tag-group ID when one exists. Public article references retrieved for that event. Article ID. Article title. Source document URL when available. The `attachments`, `tags`, and `usedArticles` arrays can be intentionally empty for events that do not include files, labels, or retrieved articles. ```json 200 OK theme={null} [ { "id": "evt_01J4W6B9Y8P2W1K4N5Q6R7S8T9", "interactionId": "int_01J4W69F8W2H3J4K5M6N7P8Q9R", "createdAt": 1723036800000, "role": "user", "type": "message", "message": "Where is my order?", "externalId": null, "externalCreatedAt": null, "csatRating": null, "feedback": null, "approved": null, "resolved": null, "attachments": [], "tags": [], "usedArticles": [] }, { "id": "evt_01J4W6C1D2E3F4G5H6J7K8L9M0", "interactionId": "int_01J4W69F8W2H3J4K5M6N7P8Q9R", "createdAt": 1723036802400, "role": "finibot", "type": "message", "message": "Your order is currently in transit and is expected to arrive tomorrow.", "externalId": null, "externalCreatedAt": null, "csatRating": null, "feedback": null, "approved": null, "resolved": null, "attachments": [ { "gcpUrl": "https://storage.googleapis.com/fini-attachments/signed/order-summary.pdf", "gcpPath": "companies/acme/interactions/int_01J4W69F8W2H3J4K5M6N7P8Q9R/order-summary.pdf", "originalUrl": "", "contentType": "application/pdf", "expiresAt": 1723040402400, "sizeBytes": 184320 } ], "tags": [ { "id": "tag_shipping", "name": "Shipping", "groupId": "tag_group_topics" } ], "usedArticles": [ { "id": "art_shipping_status", "title": "Order tracking and delivery status", "documentUrl": "https://help.example.com/order-tracking" } ] } ] ``` ## Errors The body is malformed. Common causes are omitting `content`, or omitting both `interactionId` and `botId`. The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `write` scope required for this route. Fini failed while resolving the bot, loading or creating the conversation, persisting the event, or generating the reply. Unknown `interactionId` or `botId` values currently surface here on the public route as well. Retry once, then investigate the conversation in [Inbox](/en/testing/inbox) if the error persists. # Generate knowledge Source: https://docs.usefini.com/en/api-reference/generate-knowledge POST https://api-prod.usefini.com/v2/knowledge/public Queue one knowledge-generation job from candidate text, with optional source or inbox linkage. Use this route when you already have the candidate content you want to turn into knowledge and need Fini to process it as a single background job. This route always requires `candidateKnowledge`. If you want Fini to generate directly from stored source content, use [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge) instead. `isDraft` defaults to `true`. ## Origins | Origin | Use it for | Extra required field | | ----------- | -------------------------------------------------------------------- | -------------------- | | `generated` | Raw candidate text that is not tied to another Fini record | None | | `sources` | Candidate text you want to associate with one ingested source record | `documentId` | | `inbox` | Candidate text you want to associate with one inbox event | `hcEventId` | ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Candidate content to turn into knowledge. Origin for the content. Allowed values are `sources`, `generated`, and `inbox`. Required when `origin` is `sources`. This is the ingested source ID you want to link the generated result to. Required when `origin` is `inbox`. This is the inbox event ID you want to link the generated result to. Optional operation restrictions passed through to the generation pipeline. Use this to limit what Fini is allowed to do when it decides how to apply the generated knowledge. Additional generation instructions. Optional agent ID to scope the generated content to. Whether the generated result should remain a draft. ## `restrictedOps` values Use `restrictedOps` to limit the operation choices available to the knowledge-generation pipeline for that request. | Value | Meaning | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `ADD_ARTICLE_TO_FOLDER` | Allow Fini to create a new article in an existing folder. | | `UPDATE_ARTICLE` | Allow Fini to update an existing article that the pipeline selects as the best match. | | `DO_NOTHING` | Allow Fini to decide that no knowledge change should be applied. When `isDraft` is `true`, this still creates a reviewable draft/no-op record. | ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/knowledge/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "candidateKnowledge": "Customers on annual plans can cancel at the end of the current billing term.", "origin": "generated", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "isDraft": true }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/knowledge/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "candidateKnowledge": "Customers on annual plans can cancel at the end of the current billing term.", "origin": "generated", "botId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "isDraft": True, }, ) job = response.json() ``` ```javascript Node.js theme={null} const response = await fetch("https://api-prod.usefini.com/v2/knowledge/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ candidateKnowledge: "Customers on annual plans can cancel at the end of the current billing term.", origin: "generated", botId: "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", isDraft: true, }), }); const job = await response.json(); ``` ## Response Background job ID for the queued generation request. ```json 200 OK theme={null} { "backgroundJobId": "4cfcf2cc-7a06-4de2-b460-5b991fe6236a" } ``` ## Next step Poll the queued job with [Check knowledge jobs](/en/api-reference/check-knowledge-jobs). If you left `isDraft` at its default `true`, review or publish the resulting draft before expecting live agent answers to change. ## Errors The request body is malformed, `candidateKnowledge` is missing, `origin` is invalid, or the origin-specific required field is missing. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. Expected when `isDraft` was left at its default `true`. Poll the job status, then review or publish the resulting draft through the article workflow. Fini failed while queueing or processing the generation job. Retry once, then inspect the job with [Check knowledge jobs](/en/api-reference/check-knowledge-jobs). # Get active Refine with AI session Source: https://docs.usefini.com/en/api-reference/get-active-fix-review-session GET https://api-prod.usefini.com/v2/fix-review/interactions/{id}/events/{eventId}/session/public Get the active Refine with AI session and iteration history for one Fini response. Returns the active Refine with AI session for one Fini response, including every iteration, generated recommendation, and answer replay. Returns JSON `null` when the response has no active session. Use this route when your UI or automation is anchored to a specific conversation response and needs the current active review, regardless of which iteration was most recently queued. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Conversation ID containing the reviewed response. ID of the Fini response targeted by the review session. The event must belong to the conversation and have a linked user event. ## Request example ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/fix-review/interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/events/f61a9a11-2c3b-4704-8f57-7078854d87cf/session/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests interaction_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" event_id = "f61a9a11-2c3b-4704-8f57-7078854d87cf" response = requests.get( f"https://api-prod.usefini.com/v2/fix-review/interactions/{interaction_id}/events/{event_id}/session/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) session = response.json() ``` ```javascript Node.js theme={null} const interactionId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const eventId = "f61a9a11-2c3b-4704-8f57-7078854d87cf"; const response = await fetch( `https://api-prod.usefini.com/v2/fix-review/interactions/${interactionId}/events/${eventId}/session/public`, { headers: { Authorization: "Bearer fini_your_api_key" } } ); const session = await response.json(); ``` ## Response Returns a `FixReviewSession` object or JSON `null`. `iterations` is ordered by `iterationNumber` descending, and `latestIteration` duplicates its first item for convenient polling. ```json 200 OK theme={null} { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "status": "resolved", "source": "widget", "user": { "name": "Sam Lee", "email": "customer@example.com" }, "messages": [ { "role": "user", "content": "How do refunds work?", "createdAt": "2026-07-28T08:55:32.000Z" }, { "role": "assistant", "content": "Refunds are available within 30 days.", "createdAt": "2026-07-28T08:55:40.000Z" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Using the result Poll this endpoint until `latestIteration.status` reaches a terminal state: * `ready`: review the replayed answer and proposed changes. * `no_change`: Fini completed the analysis but did not find an actionable prompt, knowledge, or rule fix. * `failed`: inspect `latestIteration.error` before retrying or escalating. For a `ready` iteration: * Compare `latestIteration.oldAnswerSnapshot.content` with `latestIteration.newAnswerSnapshot.content` to see whether the replay improved the answer. * Use `latestIteration.replayInteractionId` and `latestIteration.replayEventId` to open or fetch the replayed conversation and answer. * Inspect `latestIteration.changes`. Each change includes `changeType`, a draft ID when Fini created one, and `rootCause` with the diagnosed failure mode and target details. The session response does not apply the fix. A prompt, knowledge, or rule recommendation becomes live only after the corresponding draft is reviewed and published. ## FixReviewSession object | Field | Type | Description | | ------------------------ | ------------------------ | -------------------------------------------------------------------------------- | | `id` | string | Fix-review session ID. | | `companyId` | string | Workspace ID. | | `interactionId` | string | Reviewed conversation ID. | | `targetEventId` | string | Original Fini response under review. | | `targetUserEventId` | string \| null | Linked user event used to replay the response. | | `status` | string | `active`, `published`, or `closed`. This route only returns an `active` session. | | `publishedIterationId` | string \| null | Iteration applied from this session, when present. | | `publishedAt` | string \| null | ISO 8601 publication timestamp. | | `closedAt` | string \| null | ISO 8601 close timestamp. | | `closedReason` | string \| null | Reason the session was closed. | | `createdAt` | string | ISO 8601 creation timestamp. | | `updatedAt` | string | ISO 8601 last-update timestamp. | | `originalAnswerSnapshot` | `AnswerSnapshot` \| null | Snapshot of the original response. | | `latestIteration` | `FixIteration` \| null | Most recent iteration. | | `iterations` | `FixIteration[]` | All iterations, newest first. | | Field | Type | Description | | --------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------- | | `id` | string | Iteration ID. | | `companyId` | string | Workspace ID. | | `sessionId` | string | Parent session ID. | | `interactionId` | string | Reviewed conversation ID. | | `targetEventId` | string | Original Fini response under review. | | `previousIterationId` | string \| null | Previous iteration in the session. | | `backgroundJobId` | string \| null | Processing job ID. | | `replayInteractionId` | string \| null | Conversation created for the replay. | | `replayEventId` | string \| null | Generated answer event from the replay. | | `iterationNumber` | number | One-based revision number within the session. | | `status` | string | `queued`, `generating_changes`, `replaying`, `ready`, `no_change`, `failed`, `published`, or `superseded`. | | `feedbackNote` | string | Feedback supplied when the iteration was created. | | `summary` | string \| null | Generated summary of the recommendation. | | `confidence` | string \| null | `high`, `medium`, `low`, or `null`. | | `error` | string \| null | Processing error for a failed iteration. | | `publishedAt` | string \| null | ISO 8601 publication timestamp. | | `startedAt` | string \| null | ISO 8601 processing-start timestamp. | | `completedAt` | string \| null | ISO 8601 completion timestamp. | | `createdAt` | string | ISO 8601 creation timestamp. | | `updatedAt` | string | ISO 8601 last-update timestamp. | | `oldAnswerSnapshot` | `AnswerSnapshot` \| null | Answer used as the baseline for this iteration. | | `newAnswerSnapshot` | `AnswerSnapshot` \| null | Answer generated by the replay. | | `changes` | `FixChange[]` | Suggested prompt, knowledge, or rule changes. | | Field | Type | Description | | ----------------- | -------------- | --------------------------------------------------------------------- | | `interactionId` | string | Conversation containing the answer. | | `eventId` | string | Answer event ID. | | `originalEventId` | string \| null | Optional original event referenced by a replay event, when available. | | `content` | string \| null | Answer content. | | `role` | string | Event role. The reviewed answer is normally `finibot`. | | `type` | string | Event type. | | `createdAt` | string | ISO 8601 event timestamp. | | Field | Type | Description | | ---------------------- | -------------- | ---------------------------------------------------------------------------------- | | `id` | string | Change ID. | | `companyId` | string | Workspace ID. | | `sessionId` | string | Parent session ID. | | `iterationId` | string | Parent iteration ID. | | `interactionId` | string | Reviewed conversation ID. | | `targetEventId` | string | Reviewed Fini response ID. | | `rootCause` | object | Diagnosed failure and target details. See [Root cause object](#root-cause-object). | | `changeType` | string | `update_prompt`, `update_rule`, `create_article`, or `update_article`. | | `draftPromptVersionId` | string \| null | Draft prompt version created for a prompt recommendation. | | `draftArticleId` | string \| null | Draft article created for a knowledge recommendation. | | `draftRuleVersionId` | string \| null | Draft rule version created for a rule recommendation. | | `createdAt` | string | ISO 8601 creation timestamp. | ### Root cause object `rootCause` includes the failure classification and the target Fini should change: * `failureStage`, such as `planning`, `knowledge_search`, `knowledge_content`, `rule_execution`, `instruction_resolution`, or `answer_generation`. * `failureMode`, such as `required_search_skipped`, `incorrect_knowledge`, or `required_information_omitted`. * `reasoning`, explaining why Fini selected this failure. * `target.kind`, which is `prompt`, `kb_article`, or `rule`. * `target.operation`, which is `create` or `update` when the target supports both. * Target-specific identifiers and fields, such as prompt section IDs, knowledge article IDs, editable knowledge fields, or rule IDs. Use the draft ID on the `FixChange` record to inspect the generated artifact in the relevant Fini surface. Use `rootCause` to explain why that artifact was proposed. ### Fix-change enum values `changeType` can be: * `update_prompt` * `update_rule` * `create_article` * `update_article` `failureMode` depends on `failureStage`. Common values include `required_search_skipped`, `relevant_knowledge_not_available`, `incorrect_knowledge`, `required_rule_behavior_missing`, `required_instruction_omitted`, and `required_information_omitted`. ## Errors The event does not belong to the conversation, is not Fini-authored, or has no linked user event for replay. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The conversation or target event does not exist in the workspace. Fini could not load the Refine with AI session or its related records. # Get article history version Source: https://docs.usefini.com/en/api-reference/get-article-history-version POST https://api-prod.usefini.com/v2/hc-articles/{id}/history/public Fetch one saved article version by version number. Fetches one saved version of an article from its history. This route is `read`-scoped even though it uses `POST`, because the version number is passed in the request body. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. `application/json` ## Path parameters Article ID. ## Body parameters Article version number to fetch. ## Response ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "version": 0 }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'version': 0 } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "version": 0 }, ) data = response.json() ``` ```json 200 OK theme={null} [ { "versionId": "v3", "version": 3, "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "item": { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } } ] ``` Returns the article as it existed at the requested version. # Get articles by IDs Source: https://docs.usefini.com/en/api-reference/get-articles-by-ids POST https://api-prod.usefini.com/v2/hc-articles/ids/public Fetch one or more articles by ID. Use this route when you want direct lookup by one or more article IDs. If you want to fetch a single article by ID, send a single-item `articleIds` array. There is no workspace-API-key `GET /v2/hc-articles/:id/public` route in the current controller. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. `application/json` ## Body parameters Article IDs to fetch in one request. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/ids/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "articleIds": ["7f5392e5-dc7d-4558-8860-cf3ea4b32f94"] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/ids/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'articleIds': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/ids/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "articleIds": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Response Returns an array of the article objects that were found in the workspace. Each item uses the shared object defined in [Manage knowledge](/en/api-reference/manage-knowledge). The current route returns the articles it finds. It does not reject the request just because some requested IDs are missing. ## Errors The request body is malformed or `articleIds` is missing. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope. # Get Business Rule Source: https://docs.usefini.com/en/api-reference/get-business-rule GET https://api-prod.usefini.com/v2/hc-rules/{id}/public Fetch one Business Rule with its full tree. Returns one Business Rule as a full [`Rule`](/en/api-reference/rules#rule-object). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Business Rule ID. ## Response Returns the Business Rule with `flowConfig`, `source`, `triggerType`, `inputSchema`, `defaultRuleId`, and assigned `botIds` when applicable. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The Business Rule does not exist in your workspace. # Get Business Rule fields context Source: https://docs.usefini.com/en/api-reference/get-business-rule-fields-context GET https://api-prod.usefini.com/v2/hc-rules/fields-context/public Get the fields and resources available to Business Rule trees. Returns the workspace resources and built-in runtime context that can be referenced by a Business Rule tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Send `business`. ## Response Workspace user attributes with their input and output schemas. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/fields-context/public?type=intent", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "contextFields": [ { "path": "conversation.source", "dataType": "string" } ], "operatorTypes": [ "==", "!=", "contains" ], "templates": [ { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] } ``` Workspace actions available to Tool nodes. Fini-provided actions available to Tool nodes. Input tag groups and their tags. Widget forms and their typed fields. Built-in escalation and integration fields available to Business Rules. Condition operators as `{ value, label }` objects. Array quantifiers as `{ value, label }` objects. Interaction sources available in the workspace. ## Errors `type` is not a supported rule type. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. # Get conversation Source: https://docs.usefini.com/en/api-reference/get-conversation GET https://api-prod.usefini.com/v2/hc-interactions/{id}/public Fetch one public conversation by ID. Returns the same shape as a single item from List conversations. Returns one conversation record by ID for the workspace tied to your API key. The response shape is identical to a single entry in [List conversations](/en/api-reference/list-conversations): same fields, same nested `events[]` objects, and the same public article, folder, tag, and attachment semantics. Use [List conversations](/en/api-reference/list-conversations) to discover conversation and event IDs. Use [Send conversation feedback](/en/api-reference/send-feedback-conversation) to rate an event, [Create fix-review iteration](/en/api-reference/create-fix-review-iteration) to analyze a Fini response, or [Generate Answer](/en/api-reference/generate-answer) to send a new turn into Fini. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Conversation ID to fetch. Get this from [List conversations](/en/api-reference/list-conversations). The public [Generate Answer](/en/api-reference/generate-answer) response is event-only, so use the list route if you need to discover a newly created conversation ID. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests conversation_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.get( f"https://api-prod.usefini.com/v2/hc-interactions/{conversation_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) conversation = response.json() ``` ```javascript Node.js theme={null} const conversationId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/${conversationId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const conversation = await response.json(); ``` ## Response The response is a single `PublicConversation` object. See [List conversations → PublicConversation](/en/api-reference/list-conversations#nested-objects) for the full field reference and nested object definitions. ```json 200 OK theme={null} { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "status": "resolved", "source": "widget", "user": { "name": "Sam Lee", "email": "customer@example.com" }, "messages": [ { "role": "user", "content": "How do refunds work?", "createdAt": "2026-07-28T08:55:32.000Z" }, { "role": "assistant", "content": "Refunds are available within 30 days.", "createdAt": "2026-07-28T08:55:40.000Z" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` Current controller behavior: unknown, already-deleted, or inaccessible conversation IDs surface as `500 Internal Server Error` on this public route rather than a dedicated `404 Not Found`. ## Errors The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `read` scope required for this route. Fini failed while loading the conversation. Unknown, already-deleted, or workspace-mismatched IDs currently surface here on the public route as well. # Get event metadata Source: https://docs.usefini.com/en/api-reference/get-event-metadata GET https://api-prod.usefini.com/v2/hc-events/{id}/metadata Fetch reasoning, knowledge, tag, attribute, and rule metadata for one Fini-authored event. Returns execution metadata for one Fini-authored event in your workspace. Use this endpoint when a conversation export tells you which event to inspect, but you need the detailed trace behind that response: planning, knowledge search, answer reasoning, tag selection, executed Attributes, and executed Rules. Use [List conversations](/en/api-reference/list-conversations) or [Get conversation](/en/api-reference/get-conversation) to discover event IDs. This route only returns metadata for events where `role` is `finibot`. This public API route is currently registered as `/v2/hc-events/{id}/metadata`, without the `/public` suffix used by most other public endpoints. It still requires a workspace API key with `read` scope. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Event ID to inspect. The event must belong to your workspace and have `role: "finibot"`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-events/2f7dcb2f-2a41-4f5d-a4ad-2b6cbf61d20a/metadata' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests event_id = "2f7dcb2f-2a41-4f5d-a4ad-2b6cbf61d20a" response = requests.get( f"https://api-prod.usefini.com/v2/hc-events/{event_id}/metadata", headers={"Authorization": "Bearer fini_your_api_key"}, ) metadata = response.json() ``` ```javascript Node.js theme={null} const eventId = "2f7dcb2f-2a41-4f5d-a4ad-2b6cbf61d20a"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-events/${eventId}/metadata`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const metadata = await response.json(); ``` ## Response Planning trace for the response, including reasoning and whether Fini decided to run knowledge search. Knowledge-search trace, including top-result reasoning, selection reasoning, and the articles considered for the response. Answer-generation reasoning items returned by the model trace. Input tag-selection reasoning and chosen tags, when input tags were selected for the event. Output tag-selection reasoning and chosen tags, when output tags were selected for the event. Attribute executions exposed for this event, including tool names, success state, extracted data, and external API step results when available. Rule execution details for the selected rule, including `ruleId`, `ruleName`, and node execution results when available. ```json 200 OK theme={null} { "planning": { "reasoning": "The customer is asking about refund eligibility, so knowledge search is needed.", "performKnowledgeSearch": true }, "knowledgeSearch": { "topOneReasoning": "The refund policy article directly answers the question.", "selectionReasoning": "Selected the most recent public refund policy article.", "articles": [ { "id": "7f1a8c7e-20db-4511-9b7b-95d894f9d1b2", "title": "Refund policy", "version": 3 } ] }, "generateAnswer": { "reasoning": [ { "name": "Policy grounding", "reasoning": "Use the 30-day refund window and avoid promising exceptions." } ] }, "inputTagSelection": null, "outputTagSelection": { "reasoning": "The response resolves a policy question.", "chosenTags": { "Conversation Status": ["Resolved"], "Topic": ["Refunds"] } }, "executedUserAttributes": [ { "id": "9c4b8e11-f4f5-4ef4-a82f-34bb080da8c6", "name": "Get order status", "success": true, "extractedData": { "orderStatus": "delivered" }, "results": [ { "id": "2d2a7f0e-8b3a-4f7f-9b4b-3b2e4a7a3c23", "name": "Fetch order", "success": true, "data": { "status": "delivered" } } ] } ], "executedRules": { "ruleId": "e071d8b6-a780-49fa-a3ac-01f7312b20ef", "ruleName": "Refund policy routing", "results": [ { "id": "3a70c315-0fe0-42b8-a0c2-ec2ad0fda69d", "name": "Check refund window", "type": "CONDITION", "success": true, "result": { "eligible": true } } ] } } ``` ## Errors The event ID is missing, or the event is not from the Fini bot. Only `finibot` events have this metadata response. The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `read` scope required for this route. The event does not exist or does not belong to the workspace tied to your API key. # Get Refine with AI session Source: https://docs.usefini.com/en/api-reference/get-fix-review-session GET https://api-prod.usefini.com/v2/fix-review/interactions/{id}/events/{eventId}/sessions/{sessionId}/public Get one Refine with AI session by ID, including all iterations and recommendations. Returns one Refine with AI session by ID. Unlike [Get active Refine with AI session](/en/api-reference/get-active-fix-review-session), this route can retrieve an `active`, `published`, or `closed` session. Use it after [Create Refine with AI iteration](/en/api-reference/create-fix-review-iteration) returns a `sessionId`, or when you need to load a known Refine with AI review session from history. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Conversation ID containing the reviewed response. ID of the reviewed Fini response. Refine with AI session ID returned by [Create Refine with AI iteration](/en/api-reference/create-fix-review-iteration). ## Request example ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/fix-review/interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/events/f61a9a11-2c3b-4704-8f57-7078854d87cf/sessions/91d2d432-b408-4496-920d-24ad6a1b9e87/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests interaction_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" event_id = "f61a9a11-2c3b-4704-8f57-7078854d87cf" session_id = "91d2d432-b408-4496-920d-24ad6a1b9e87" response = requests.get( f"https://api-prod.usefini.com/v2/fix-review/interactions/{interaction_id}/events/{event_id}/sessions/{session_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) session = response.json() ``` ```javascript Node.js theme={null} const interactionId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const eventId = "f61a9a11-2c3b-4704-8f57-7078854d87cf"; const sessionId = "91d2d432-b408-4496-920d-24ad6a1b9e87"; const response = await fetch( `https://api-prod.usefini.com/v2/fix-review/interactions/${interactionId}/events/${eventId}/sessions/${sessionId}/public`, { headers: { Authorization: "Bearer fini_your_api_key" } } ); const session = await response.json(); ``` ## Response Returns the same [`FixReviewSession`](/en/api-reference/get-active-fix-review-session#fixreviewsession-object) shape as the active-session route. The response includes `originalAnswerSnapshot`, `latestIteration`, and all `iterations` ordered newest first. Use `latestIteration.status` to decide whether the fix review is still running or ready to inspect. When it is `ready`, compare `latestIteration.oldAnswerSnapshot` with `latestIteration.newAnswerSnapshot`, then inspect `latestIteration.changes` for generated draft IDs and `rootCause` details. The response shows the proposed fix and replay result; it does not publish the underlying prompt, knowledge, or rule change. ```json 200 OK theme={null} { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "status": "resolved", "source": "widget", "user": { "name": "Sam Lee", "email": "customer@example.com" }, "messages": [ { "role": "user", "content": "How do refunds work?", "createdAt": "2026-07-28T08:55:32.000Z" }, { "role": "assistant", "content": "Refunds are available within 30 days.", "createdAt": "2026-07-28T08:55:40.000Z" } ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The target event is invalid for fix review, or the session does not belong to the conversation and response supplied in the path. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The conversation, event, or session does not exist in the workspace. Fini could not load the session or its related records. # Get knowledge folders Source: https://docs.usefini.com/en/api-reference/get-knowledge-folders GET https://api-prod.usefini.com/v2/hc-folders/public Return the current knowledge-tree snapshot, optionally scoped to one agent. Use this route to inspect the current knowledge folders snapshot in the workspace. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Optional agent ID. When supplied, Fini returns the tree scoped to that agent's attached folders. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-folders/public?botId=4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-folders/public?botId=2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-folders/public?botId=2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} { "folders": [ { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ], "articles": [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] } ``` ## Response Returns a knowledge folders snapshot object. See [Organize knowledge](/en/api-reference/organize-knowledge) for the shared snapshot fields. The workspace-API-key response includes `id`, `createdAt`, `updatedAt`, and `snapshotObjV2`. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope. This usually means the workspace has no folders yet, or no folders attached to the `botId` you requested. # Get replay Source: https://docs.usefini.com/en/api-reference/get-replay GET https://api-prod.usefini.com/v2/replays/{id}/public Fetch one replay conversation by ID. Returns one replay conversation record by ID. Use this when you already have a replay ID from [Create replay](/en/api-reference/create-replay) or [List replays](/en/api-reference/list-replays). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Replay conversation ID to fetch. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/replays/9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests replay_id = "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625" response = requests.get( f"https://api-prod.usefini.com/v2/replays/{replay_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) replay = response.json() ``` ```javascript Node.js theme={null} const replayId = "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625"; const response = await fetch( `https://api-prod.usefini.com/v2/replays/${replayId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const replay = await response.json(); ``` ## Response Returns the replay conversation record. Replay conversation ID. Original conversation ID this replay was created from. Replay metadata, including `target_event_id`, `status`, and optional `ml_models`. ```json 200 OK theme={null} { "id": "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625", "companyId": "6bc9f4f8-3564-4a9c-8cc0-ea1f1dd66c2d", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "source": "replay", "channel": "widget", "status": "resolved", "createdAt": "2026-07-30T12:18:03.211Z", "updatedAt": "2026-07-30T12:18:14.904Z", "parentInteractionId": "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "replay": { "target_event_id": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "status": "done", "ml_models": { "generateAnswer": "gpt-4.1" } } } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. The replay ID does not exist in the workspace. # Get replay events Source: https://docs.usefini.com/en/api-reference/get-replay-events GET https://api-prod.usefini.com/v2/replays/{id}/events/public Fetch the events for one replay conversation. Returns the formatted events for one replay conversation. Use this after [Get replay](/en/api-reference/get-replay) when you need the replayed messages and execution details rather than only the replay conversation metadata. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Replay conversation ID whose events you want to fetch. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/replays/9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625/events/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests replay_id = "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625" response = requests.get( f"https://api-prod.usefini.com/v2/replays/{replay_id}/events/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) events = response.json() ``` ```javascript Node.js theme={null} const replayId = "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625"; const response = await fetch( `https://api-prod.usefini.com/v2/replays/${replayId}/events/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const events = await response.json(); ``` ## Response Returns an array of formatted event objects. Event ID. Replay conversation ID that owns the event. Event sender role, such as `user` or `finibot`. Message content for the event, when present. Original conversation event copied into or referenced by the replay, when present. ```json 200 OK theme={null} [ { "id": "0b3a0bf5-c044-487f-93c3-fd4a8452fe96", "companyId": "6bc9f4f8-3564-4a9c-8cc0-ea1f1dd66c2d", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "interactionId": "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625", "role": "user", "type": "message", "createdAt": "2026-07-30T12:18:03.511Z", "content": "How do refunds work?", "externalCreatedAt": 1785416132511 }, { "id": "69e64e28-6fd7-47ab-806d-f573a975188f", "companyId": "6bc9f4f8-3564-4a9c-8cc0-ea1f1dd66c2d", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "interactionId": "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625", "role": "finibot", "type": "message", "createdAt": "2026-07-30T12:18:14.904Z", "content": "Refunds are available within 30 days.", "originalEventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf" } ] ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading events for the replay conversation. # Get reply rule fields context Source: https://docs.usefini.com/en/api-reference/get-reply-rule-fields-context GET https://api-prod.usefini.com/v2/reply-behavior/fields-context/public Read the fields and values available when interpreting reply rule conditions. Returns the workspace-specific attributes, output tags, installed integration sources, operators, quantifiers, and built-in fields available to reply rule conditions. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Enabled user attributes with their IDs, names, input schemas, and output schemas. Supported comparison operators. Each item contains `value` and `label`. Supported array quantifiers. Each item contains `value` and `label`. Installed reply-capable integration providers. Supported values include `intercom`, `zendesk`, `salesforce`, `gorgias`, `front`, `hubspot`, and `livechat` when installed. Output tag groups. Each group contains `id`, `name`, and a `tags` array of `{ id, name }` objects. Built-in condition fields. Each item contains `name`, `path`, `dataType`, and optional `values` or `source` constraints. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/reply-behavior/fields-context/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/reply-behavior/fields-context/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const fieldsContext = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/reply-behavior/fields-context/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) fields_context = response.json() ``` ```json 200 OK theme={null} { "userAttributes": [], "operatorTypes": [ { "value": "==", "label": "Equals" }, { "value": "!=", "label": "Not Equals" }, { "value": "contains", "label": "Contains" } ], "quantifierTypes": [ { "value": "ANY", "label": "Any" }, { "value": "ALL", "label": "All" }, { "value": "NONE", "label": "None" } ], "sources": ["intercom", "zendesk"], "tagGroups": [ { "id": "8e96d004-e59d-4c71-9940-825cc3a7e5da", "name": "Conversation topic", "tags": [ { "id": "abef2d19-fc42-4990-898a-fbcecabf11d4", "name": "Billing" } ] } ], "contextFields": [ { "name": "Integration Provider", "path": "source", "dataType": "string" }, { "name": "Channel", "path": "channel", "dataType": "string", "values": ["chat", "email"] }, { "name": "Escalated Conversation", "path": "alreadyEscalated", "dataType": "boolean" } ] } ``` # Get reply rules Source: https://docs.usefini.com/en/api-reference/get-reply-rules GET https://api-prod.usefini.com/v2/reply-behavior/public Read the workspace conditions for no reply, internal comment, and direct reply behavior. Returns all three reply rule slots for the authenticated workspace. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Returns one [reply rule collection](/en/api-reference/reply-rules#reply-rule-collection). ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/reply-behavior/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/reply-behavior/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const replyRules = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/reply-behavior/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) reply_rules = response.json() ``` ```json 200 OK theme={null} { "noReply": { "id": "1c1d72e3-9239-4f43-ad81-2bbb0b7c0312", "companyId": "228eb0c4-55d9-40c8-b9d1-dae413508164", "replyType": "NO_REPLY", "conditions": [ { "scope": "SCALAR", "predicate": [ { "left": { "path": "alreadyEscalated", "dataType": "boolean" }, "operator": "==", "right": { "value": true } } ] } ], "isEnabled": true, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:04.000Z" }, "internalComment": { "replyType": "INTERNAL_COMMENT", "conditions": [], "isEnabled": false }, "directReply": { "replyType": "DIRECT_REPLY", "conditions": [], "isEnabled": false } } ``` # Get source Source: https://docs.usefini.com/en/api-reference/get-source GET https://api-prod.usefini.com/v2/documents/public/{id} Fetch one source record by ID. Returns the same shape as the list endpoint, scoped to a single source. Returns one source record by ID. The response shape is identical to a single entry in [List sources](/en/api-reference/list-sources) — same fields, same semantics. Use this endpoint when you have a source ID and want a focused payload, especially for polling `linkedJobStatus` during ingestion. For the end-to-end flow, see [Sources](/en/api-reference/sources). For polling guidance, see [Ingest sources](/en/api-reference/ingest-sources#polling-for-completion). The route path and response object still use `document` naming because that is the current API contract. This page uses **source** terminology for the product model. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Source ID. Get this from [List sources](/en/api-reference/list-sources) or from the response of [Ingest sources](/en/api-reference/ingest-sources) and [Register provider resources](/en/api-reference/register-provider-resources). ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/documents/public/5d9f67a8-d853-4af4-b7ce-23ebba1245e5' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests source_id = "5d9f67a8-d853-4af4-b7ce-23ebba1245e5" response = requests.get( f"https://api-prod.usefini.com/v2/documents/public/{source_id}", headers={"Authorization": "Bearer fini_your_api_key"}, ) source = response.json() ``` ```javascript Node.js theme={null} const sourceId = "5d9f67a8-d853-4af4-b7ce-23ebba1245e5"; const response = await fetch( `https://api-prod.usefini.com/v2/documents/public/${sourceId}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const source = await response.json(); ``` ## Response The response is a single `Document` object. See [List sources → Document](/en/api-reference/list-sources#document) for the full field reference. In the product model, this object represents one source record. ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "source": "web", "url": "https://help.example.com/refunds", "title": "Refund policy", "success": true, "changed": false, "linkedJobStatus": "COMPLETED", "linkedKnowledgeId": "7fa27325-e2f6-4420-b705-436f9106f908", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The `id` path parameter is not a valid UUID. The API key is missing, malformed, revoked, or invalid. Confirm `Authorization: Bearer fini_...` with the full key. The API key doesn't include the `read` scope, or the source belongs to a different workspace than the key. No source exists with that ID in the workspace tied to the key. Confirm the ID and that you're authenticating against the right workspace. # Get tag Source: https://docs.usefini.com/en/api-reference/get-tag GET https://api-prod.usefini.com/v2/tags/{id}/public Fetch one tag by ID. Fetches one [`Tag`](/en/api-reference/tags#tag-object) by ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Tag ID to fetch. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/tags/76f90f08-7857-4853-bc17-2f1487516a3d/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests tag_id = "76f90f08-7857-4853-bc17-2f1487516a3d" response = requests.get( f"https://api-prod.usefini.com/v2/tags/{tag_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) tag = response.json() ``` ```javascript Node.js theme={null} const tagId = "76f90f08-7857-4853-bc17-2f1487516a3d"; const response = await fetch( `https://api-prod.usefini.com/v2/tags/${tagId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const tag = await response.json(); ``` ## Response Returns one [`Tag`](/en/api-reference/tags#tag-object). ```json 200 OK theme={null} { "id": "76f90f08-7857-4853-bc17-2f1487516a3d", "createdAt": "2026-06-12T10:16:00.000Z", "tagGroupId": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "tagName": "Track Order", "tagDescription": "Use when the customer is asking where an existing order is." } ``` ```json 200 OK (unknown ID) theme={null} null ``` Current controller behavior: unknown tag IDs currently return `200 OK` with `null` on this public route rather than a dedicated `404 Not Found`. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading the tag from storage. # Get tag group Source: https://docs.usefini.com/en/api-reference/get-tag-group GET https://api-prod.usefini.com/v2/tag-groups/{id}/public Fetch one tag group by ID. Fetches one [`TagGroup`](/en/api-reference/tag-groups#taggroup-object) by ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Tag group ID to fetch. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/tag-groups/4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests tag_group_id = "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5" response = requests.get( f"https://api-prod.usefini.com/v2/tag-groups/{tag_group_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) tag_group = response.json() ``` ```javascript Node.js theme={null} const tagGroupId = "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/${tagGroupId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const tagGroup = await response.json(); ``` ## Response Returns one [`TagGroup`](/en/api-reference/tag-groups#taggroup-object). ```json 200 OK theme={null} { "id": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "createdAt": "2026-06-12T10:14:22.000Z", "companyId": "38ba4db0-31db-4669-bb95-7b8313c4016b", "title": "Order Intent", "description": "Primary order-related intent used for routing and reporting.", "prompt": "Choose the single tag that best describes the customer's order request.", "multiselect": false, "updatedAt": "2026-06-12T10:14:22.000Z", "mandatory": false, "isOutputTagGroup": false } ``` Current controller behavior: unknown tag group IDs currently surface as `500 Internal Server Error` on this public route rather than a dedicated `404 Not Found`. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading the tag group. Unknown IDs currently surface here as well. # Get a test set Source: https://docs.usefini.com/en/api-reference/get-test-set GET https://api-prod.usefini.com/v2/test-sets/{testSetId}/public Fetch one test set with its resolved criteria. Returns a test set with its resolved criteria and conversation summaries. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Test set ID. ## Response Returns a [TestSet object](/en/api-reference/test-sets#testset-object) with a `criteria` array of [Criterion objects](/en/api-reference/test-sets#criterion-object) and a `conversations` array of conversation summaries. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/public`, { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const testSet = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.get( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) test_set = response.json() ``` ```json 200 OK theme={null} { "id": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "name": "Refund regression set", "description": "Refund-policy conversations to re-check before prompt changes.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d" ], "conversations": [ { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "subject": "Customer asks about refund eligibility" }, { "id": "2dd2b920-f57c-4e92-8a6a-f310d4c8594d", "subject": "Exchange request after delivery" } ], "criteria": [ { "id": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "defaultCriterionId": null, "name": "Goal resolution", "type": "complex_judge", "judgePrompt": "Judge whether the conversation resolved the user's goal.", "passPrompt": "The user's goal was resolved.", "failPrompt": "The user's goal was not resolved.", "condition": null, "blocking": true, "isActive": true, "createdAt": "2026-07-28T08:56:12.000Z", "updatedAt": "2026-07-28T08:56:12.000Z" } ], "createdBy": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T08:56:12.000Z" } ``` # Get fields context Source: https://docs.usefini.com/en/api-reference/get-test-set-fields-context GET https://api-prod.usefini.com/v2/test-sets/fields-context/public Read default criteria and deterministic-condition fields for Test Suite criteria. Returns default criteria plus the deterministic-condition fields, operators, and quantifiers supported by the workspace. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Fini-provided criteria that can be copied into a test set by sending `defaultCriterionId` to [Add criteria](/en/api-reference/add-test-set-criteria). Deterministic-condition fields available for the workspace. Operators supported by deterministic conditions. Quantifiers supported for array-style deterministic conditions. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/test-sets/fields-context/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/test-sets/fields-context/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const fieldsContext = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/test-sets/fields-context/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) fields_context = response.json() ``` ```json 200 OK theme={null} { "defaultCriteria": [ { "id": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "testSetId": null, "companyId": null, "defaultCriterionId": null, "name": "Goal resolution", "type": "complex_judge", "judgePrompt": "Judge whether the conversation resolved the user's goal.", "passPrompt": "The user's goal was resolved.", "failPrompt": "The user's goal was not resolved.", "condition": null, "blocking": true, "isActive": true, "createdAt": "2026-07-28T08:00:00.000Z", "updatedAt": "2026-07-28T08:00:00.000Z" } ], "contextFields": [ { "path": "knowledgeSearchUsed", "dataType": "boolean" }, { "path": "replyTypes", "dataType": "array", "values": ["message", "internal_note", "no_reply"] } ], "operatorTypes": ["==", "!=", ">", ">=", "<", "<=", "contains", "before", "after", "in", "not_in", "is_null", "is_not_null", "is_empty", "is_not_empty"], "quantifierTypes": ["ANY", "ALL", "NONE"] } ``` # Get a run Source: https://docs.usefini.com/en/api-reference/get-test-set-run GET https://api-prod.usefini.com/v2/test-sets/runs/{runId}/public Fetch one test set run and its detailed result. Fetches one run with its full result when available. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Run ID. ## Response Returns a [Run object](/en/api-reference/test-sets#run-object). While the run is queued or processing, `result` is `null`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/test-sets/runs/5afd818a-a5f9-4e1b-9619-3c7191c12d9a/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const runId = '5afd818a-a5f9-4e1b-9619-3c7191c12d9a'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/runs/${runId}/public`, { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const run = await response.json(); ``` ```python Python theme={null} import requests run_id = "5afd818a-a5f9-4e1b-9619-3c7191c12d9a" response = requests.get( f"https://api-prod.usefini.com/v2/test-sets/runs/{run_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) run = response.json() ``` ```json 200 OK theme={null} { "id": "5afd818a-a5f9-4e1b-9619-3c7191c12d9a", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "status": "completed", "result": { "summary": { "testSetResult": "pass", "totalConversations": 2, "passedConversations": 2, "failedConversations": 0, "errorConversations": 0, "totalCriteria": 2, "passedCriteria": 4, "failedCriteria": 0 }, "conversations": [ { "hcInteractionId": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "interactionSubject": "Customer asks about refund eligibility", "result": "pass", "error": null, "criteriaResults": [ { "criteriaId": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "name": "Goal resolution", "type": "complex_judge", "blocking": true, "result": "pass", "reasoning": "The answer resolved the refund-policy question.", "evidence": ["The agent explained eligibility and next steps."] } ] } ] }, "createdBy": null, "createdAt": "2026-07-28T09:01:14.000Z", "updatedAt": "2026-07-28T09:02:09.000Z" } ``` # Ingest sources Source: https://docs.usefini.com/en/api-reference/ingest-sources POST https://api-prod.usefini.com/v2/documents/public Queue first-time ingestion or refresh jobs for web links or existing source IDs. The call returns immediately because processing is async. Queues ingestion or refresh jobs for sources. This is the call that actually starts processing, both for web links, which skip registration entirely, and for provider content, where you have already called [Register provider resources](/en/api-reference/register-provider-resources). This route is asynchronous. The response only confirms the job was queued. Poll [List sources](/en/api-reference/list-sources) or [Get source](/en/api-reference/get-source) and watch `linkedJobStatus`, `success`, and `error` to track progress. The request body still uses `documentIdsToAdd` and `documentIdsToRefresh` because that is the current API contract. On this page, those values are described as source inputs or source IDs. ## Add sources with this endpoint `POST /v2/documents/public` is the add-sources endpoint for both web content and connected providers: * For `web`, place URLs directly in `documentIdsToAdd`. * For `zendesk`, `confluence`, and `notion`, first use [List provider resources](/en/api-reference/list-provider-resources) and [Register provider resources](/en/api-reference/register-provider-resources), then place the returned source IDs in `documentIdsToAdd`. | Input type | What goes in `documentIdsToAdd` | Notes | | ------------ | ---------------------------------- | --------------------------------------------------------------------------------- | | `web` | URLs | You can optionally crawl first with `POST /v2/documents/public/deep-crawl/links`. | | `zendesk` | Source IDs returned after register | Discovery response is a nested category tree. | | `confluence` | Source IDs returned after register | Discovery response is an array of spaces with nested pages. | | `notion` | Source IDs returned after register | Discovery response is a flat array of resources. | Crawling is not part of `POST /v2/documents/public` itself. If you want Fini to expand a seed URL into more pages first, call `POST /v2/documents/public/deep-crawl/links`, then send the returned URLs into `documentIdsToAdd` on this route. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Source type. Supported values: `web`, `googledrive`, `notion`, `zendesk`, `confluence`. Determines what the `documentIdsToAdd` and `documentIdsToRefresh` arrays contain. Items to ingest for the first time. **For `source: "web"`, these values are URLs.** For every other source, these values are source IDs returned by [Register provider resources](/en/api-reference/register-provider-resources) or already in your workspace. Items to refresh. Same value semantics as `documentIdsToAdd`: URLs for `web`, source IDs for everything else. Whether to apply English-specific processing. Whether to apply BASER processing. The same field names carry different value types depending on `source`. This is the most common cause of failed web imports. ```bash Web cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/documents/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "source": "web", "documentIdsToAdd": [ "https://docs.example.com/billing/refunds", "https://docs.example.com/billing/invoices" ], "documentIdsToRefresh": [], "english": true, "baser": false }' ``` ```bash Provider cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/documents/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "source": "notion", "documentIdsToAdd": [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5" ], "documentIdsToRefresh": [], "english": true, "baser": false }' ``` ```python Python theme={null} import requests # Web import — values are URLs response = requests.post( "https://api-prod.usefini.com/v2/documents/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "source": "web", "documentIdsToAdd": [ "https://docs.example.com/billing/refunds", ], "documentIdsToRefresh": [], "english": True, "baser": False, }, ) data = response.json() ``` ```javascript Node.js theme={null} // Provider import — values are document IDs from Register const response = await fetch( "https://api-prod.usefini.com/v2/documents/public", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ source: "notion", documentIdsToAdd: ["5d9f67a8-d853-4af4-b7ce-23ebba1245e5"], documentIdsToRefresh: [], english: true, baser: false, }), } ); const data = await response.json(); ``` ## Response Source IDs for items that were queued for first-time ingestion. Source IDs for items that were queued for refresh. ```json 202 Accepted theme={null} { "jobs": [ { "id": "job_01j4fq3f0p7mef4p2j2h2vp4my", "documentId": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "status": "PENDING" } ], "documents": [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "source": "web", "url": "https://help.example.com/refunds", "title": "Refund policy", "success": true, "changed": false, "linkedJobStatus": "COMPLETED", "linkedKnowledgeId": "7fa27325-e2f6-4420-b705-436f9106f908", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] } ``` ## Polling for completion The response above means jobs are queued, not finished. Poll the read routes: ```bash Poll theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/documents/public/5d9f67a8-d853-4af4-b7ce-23ebba1245e5' \ --header 'Authorization: Bearer fini_your_api_key' ``` Watch these fields on the document record: | Field | Meaning | | ------------------- | --------------------------------------------------- | | `linkedJobStatus` | `PENDING` → `IN_PROGRESS` → `COMPLETED` or `FAILED` | | `success` | `true` when the latest run produced usable content | | `error` | Non-empty string when the latest run failed | | `paragraphs` | Populated after a successful run | | `linkedKnowledgeId` | Set once the document has been linked to an article | A `COMPLETED` job means the source was processed. It does not mean its content is live in agent answers. Source ingestion still needs to flow through [Knowledge](/en/api-reference/knowledge), and review is the recommended step before publishing. ## Errors Common causes: unsupported `source` value, missing required fields, or passing source IDs in `documentIdsToAdd` when `source: "web"` because web imports expect URLs. The API key is missing, malformed, revoked, or invalid. Confirm `Authorization: Bearer fini_...` with the full key. The API key doesn't include the `write` scope, or it's scoped to a different workspace. The job was queued successfully but failed during fetch. Check `error` on the document record. Common causes: URL behind authentication, robots.txt blocks, or content type Fini doesn't extract. The provider connection may have expired or lost permissions on the resource. Reconnect the provider in the dashboard and refresh the source. Ingestion is queued. Under heavy workspace load, `PENDING` can persist longer than usual. If a job sits for more than 15 minutes, contact support with the `linkedJobId` from the source record. # Initialize knowledge folders Source: https://docs.usefini.com/en/api-reference/initialize-knowledge-folders POST https://api-prod.usefini.com/v2/knowledge/public/tree/initialize Generate a downloadable tree-import template file from an initialization prompt. Use this route when you are setting up knowledge folders for the first time and want Fini to scaffold a starting folder-and-article structure. This route returns a downloadable file, not JSON. Save the response body using the returned `Content-Type` and `Content-Disposition` headers, then import that file with [Persist knowledge folders](/en/api-reference/persist-knowledge-folders). ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Prompt describing the folder-and-article structure you want Fini to scaffold. ## Response The response body is a generated tree template file. Downloadable tree-import template file. MIME type for the returned file. Attachment header containing the suggested filename. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/knowledge/public/tree/initialize' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "initPrompt": "Create a support knowledge tree for billing, shipping, and returns." }' \ --output fini-tree-template.csv ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/knowledge/public/tree/initialize', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'initPrompt': 'Answer only from approved knowledge and escalate if unsure.' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/knowledge/public/tree/initialize", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "initPrompt": "Answer only from approved knowledge and escalate if unsure." }, ) data = response.json() ``` ```json 200 OK theme={null} { "folders": [ { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ], "articles": [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] } ``` ## Next step Review the generated file, make any edits you want, then upload it with [Persist knowledge folders](/en/api-reference/persist-knowledge-folders). ## Errors The request body is malformed or `initPrompt` is missing or empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. Fini failed while generating the tree template. Retry once, then narrow the prompt if the failure persists. # Overview Source: https://docs.usefini.com/en/api-reference/knowledge Generate knowledge from sources, manage live articles, organize the tree, and assign knowledge to agents. Knowledge is the live side of Fini. [Sources](/en/api-reference/sources) feed into it, agents retrieve from it, and these routes let you generate, manage, organize, and assign that knowledge. There are two ways to work with knowledge in the public API. The recommended self-serve path is source-backed: ingest sources, generate drafts or live knowledge, review if needed, then organize and assign that knowledge. The advanced/manual path is to write and manage articles directly through [Manage knowledge](/en/api-reference/manage-knowledge). ## Reference pages `POST /v2/knowledge/public/tree/initialize` — generate a downloadable tree template for first-time structure setup. `POST /v2/knowledge/public/tree/persist` — import a tree file into the workspace knowledge graph. `POST /v2/knowledge/public` — queue one knowledge-generation job from candidate text. `POST /v2/knowledge/public/bulk` — queue generate-and-save jobs for multiple source IDs. `POST /v2/knowledge/public/jobs/status` — poll one or more background jobs by ID. Read, create, update, draft, publish, inspect history, revert, and delete live articles. Read the knowledge tree, manage folders, move articles between folders, and assign them to agents. ## Recommended paths ### Source-backed self-serve path Start from [Sources](/en/api-reference/sources) and ingest the raw content you want to turn into knowledge. If this is the first knowledge setup in the workspace, use [Initialize knowledge folders](/en/api-reference/initialize-knowledge-folders) and [Persist knowledge folders](/en/api-reference/persist-knowledge-folders) to scaffold the initial folder structure. Use [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge) for source-backed generation, or [Generate knowledge](/en/api-reference/generate-knowledge) when you already have candidate text. Use [Check knowledge jobs](/en/api-reference/check-knowledge-jobs), then review or publish drafts before expecting live agent answers to change. Use [Organize knowledge](/en/api-reference/organize-knowledge) to shape the tree and attach the relevant folders to agents. ### Direct manual path Use [Manage knowledge](/en/api-reference/manage-knowledge) when you already know the live articles you want to create or update, and use [Organize knowledge](/en/api-reference/organize-knowledge) when you need to change the tree or agent visibility around them. ## Endpoint map ### Knowledge generation | Method | Path | Scope | Purpose | | ------ | -------------------------------------- | ------- | --------------------------------------------------------------------- | | `POST` | `/v2/knowledge/public/tree/initialize` | `write` | Generate a tree-import template file from an initialization prompt. | | `POST` | `/v2/knowledge/public/tree/persist` | `write` | Upload a tree file and persist it into the workspace knowledge graph. | | `POST` | `/v2/knowledge/public` | `write` | Queue one knowledge-generation job from candidate text. | | `POST` | `/v2/knowledge/public/bulk` | `write` | Queue generate-and-save jobs for multiple source IDs. | | `POST` | `/v2/knowledge/public/jobs/status` | `read` | Check status for one or more background knowledge jobs. | ### Manage knowledge | Method | Path | Scope | Purpose | | -------- | ------------------------------------ | ------- | --------------------------------------------------------- | | `GET` | `/v2/hc-articles/public` | `read` | List articles. Use `type=live` or `type=draft` to filter. | | `POST` | `/v2/hc-articles/ids/public` | `read` | Fetch one or more articles by ID. | | `POST` | `/v2/hc-articles/public` | `write` | Create a live article or draft article. | | `PUT` | `/v2/hc-articles/:id/public` | `write` | Update an existing article. | | `POST` | `/v2/hc-articles/:id/draft/public` | `write` | Create a draft from an existing live article. | | `POST` | `/v2/hc-articles/:id/publish/public` | `write` | Publish a draft article. | | `GET` | `/v2/hc-articles/:id/history/public` | `read` | List saved history versions for one article. | | `POST` | `/v2/hc-articles/:id/history/public` | `read` | Fetch one saved article version by version number. | | `POST` | `/v2/hc-articles/:id/revert/public` | `write` | Revert an article to a saved history version. | | `DELETE` | `/v2/hc-articles/:id/public` | `write` | Delete an article. | ### Organize knowledge | Method | Path | Scope | Purpose | | -------- | ------------------------------------ | ------- | --------------------------------------------------------------------------- | | `GET` | `/v2/hc-folders/public` | `read` | Return the current knowledge-tree snapshot, optionally filtered by `botId`. | | `POST` | `/v2/hc-folders/public` | `write` | Create a folder in the knowledge tree. | | `PUT` | `/v2/hc-folders/:id/public` | `write` | Update a folder's title, description, or active state. | | `PUT` | `/v2/hc-folders/:id/move/public` | `write` | Move a folder under a different parent. | | `PUT` | `/v2/hc-articles/:id/move/public` | `write` | Move an article into a different folder. | | `DELETE` | `/v2/hc-folders/:id/public` | `write` | Delete a folder. | | `POST` | `/v2/hc-bot-folder-junctions/public` | `write` | Assign or unassign folders to agents in bulk. | The article read surface is now unified under `GET /v2/hc-articles/public`. There is no workspace-API-key `GET /v2/hc-articles/:id/public` route in the current controller. If you need a direct lookup by ID, use `POST /v2/hc-articles/ids/public` with one or more `articleIds`. # List article history Source: https://docs.usefini.com/en/api-reference/list-article-history GET https://api-prod.usefini.com/v2/hc-articles/{id}/history/public List saved history versions for one article. Returns the saved history versions for one article. Use it before fetching or reverting to a specific version. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Article ID. ## Response ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/history/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "versionId": "v3", "version": 3, "createdAt": "2026-07-28T08:55:32.000Z", "createdBy": "api", "item": { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } } ] ``` Returns an array of partial article records for the article's history versions. # List articles Source: https://docs.usefini.com/en/api-reference/list-articles GET https://api-prod.usefini.com/v2/hc-articles/public List live articles, draft articles, or both. Use this route to read the current articles in the workspace. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Optional filter. Allowed values: `live` and `draft`. If omitted, the route returns both live and draft articles. Optional lower bound on `updatedAt`. In practice this is usually an ISO 8601 timestamp. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-articles/public?type=live&from=2026-06-01T00:00:00.000Z' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/public?type=live&from=2026-06-01T00:00:00.000Z', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-articles/public?type=live&from=2026-06-01T00:00:00.000Z", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Response Returns an array of article objects sorted by `updatedAt` descending. Each item uses the shared object defined in [Manage knowledge](/en/api-reference/manage-knowledge), including fields such as `id`, `title`, `mainKnowledge`, `parentFolderId`, timestamps, and optional draft metadata. If you omit `type`, the array can include both live articles and draft articles. ## Errors The query parameters are malformed or `type` is not one of the allowed values. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope. # List Business Rules Source: https://docs.usefini.com/en/api-reference/list-business-rules GET https://api-prod.usefini.com/v2/hc-rules/public List Business Rules in the workspace. Returns Business Rules in the workspace as summary objects. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Send `business`. Optional source filter. The current enum value is `widget`. ## Response Returns an array of [`Rule summary`](/en/api-reference/rules#rule-summary-object) objects without `flowConfig`. Each item includes its `botIds`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/public?type=intent&source=web' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/public?type=intent&source=web', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/public?type=intent&source=web", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` Business Rules are not versioned. Do not send `includeVersions`; `versionStatus=DRAFT` returns an empty array. ## Errors A query parameter is malformed or uses an unsupported enum value. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading Business Rules. # List conversations Source: https://docs.usefini.com/en/api-reference/list-conversations GET https://api-prod.usefini.com/v2/hc-interactions/public Read all Fini conversations for your workspace, sorted newest first, with cursor pagination. Reads conversations for the workspace tied to your API key. Use it to export conversations into your own systems for analytics, QA review, or downstream processing. This is the read path described on the [API overview](/en/api-reference/overview). It pulls data *out* of Fini and does not change agent behavior. Results are sorted by latest message time, newest first. Use [List agents](/en/api-reference/list-agents) to look up the `botId` values accepted by this endpoint's optional agent filter. If you already know a conversation ID, use [Get conversation](/en/api-reference/get-conversation). If you need to send a new turn into Fini, use [Generate Answer](/en/api-reference/generate-answer). This page is export-only. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Inclusive start of the Fini ingestion window in Unix epoch milliseconds. Returns conversations whose `createdAt` is greater than or equal to this value. If omitted, Fini defaults to the last 7 days. Inclusive end of the Fini ingestion window in Unix epoch milliseconds. Returns conversations whose `createdAt` is less than or equal to this value. If omitted, Fini defaults to the current time. Maximum number of conversations to return. Minimum `1`, maximum `100`. Conversation ID to paginate from. Pass the `nextCursor` or `prevCursor` value returned by the previous response. Pagination direction when a cursor is supplied. **Note the inverted mapping:** `next` moves to *older* conversations; `previous` moves back toward *newer* ones. This is because results are sorted newest first, so "next page" goes further back in time. Optional agent ID filter. When provided, only conversations for that agent are returned. Optional comma-separated conversation sources. Supported values: `api`, `widget`, `ui`, `standalone`, `testsuite`, `replay`, `zendesk`, `intercom`, `front`, `hubspot`, `salesforce`, `gorgias`, `livechat`, `slack`, `discord`, `freshdesk`, `freshchat`, and `deskpro`. Optional comma-separated channel filter. Case-insensitive text filter over user messages. Matches conversations where at least one user message contains the provided text. Case-insensitive text filter over Fini bot messages. Matches conversations where at least one Fini-authored answer contains the provided text. Filter by CSAT rating. Accepted values are integers from `0` through `5`. Case-insensitive substring to find in customer messages. The value can contain up to 100 characters. Literal `%` and `_` characters are rejected. Case-insensitive substring to find in Fini-generated agent messages. The value can contain up to 100 characters. Literal `%` and `_` characters are rejected. The `since` / `until` window cannot exceed **90 days**, and `since` must be strictly earlier than `until`. A request where `since == until` is rejected for the same reason and returns `400 Bad Request`. Additional behavior worth knowing: * The endpoint only returns conversations where **Fini has touched the conversation**. * `since` and `until` filter the Fini ingestion timestamp in `createdAt`. They do not filter `externalCreatedAt` or event timestamps. * `source` and `channel` accept either comma-separated values or repeated query params if your HTTP client sends arrays. * `question` and `answer` are each limited to 100 non-blank characters. They cannot include `%`, `_`, or control characters. * When both message filters are supplied, a conversation must contain a matching customer message and a matching Fini-generated agent message. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-interactions/public?limit=25&channel=chat&source=widget,ui&question=refund' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-interactions/public", headers={"Authorization": "Bearer fini_your_api_key"}, params={ "limit": 25, "channel": "chat", "source": "widget,ui", "question": "refund", }, ) data = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams({ limit: "25", channel: "chat", source: "widget,ui", question: "refund", }); const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/public?${params.toString()}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const data = await response.json(); ``` ## Response Array of `PublicConversation` objects returned for the requested window and filters. See [PublicConversation](#nested-objects). Whether more results exist beyond the current page. Cursor to use when paginating forward. `null` if there is no next page. Cursor to use when paginating backward. `null` if there is no previous page. ```json 200 OK theme={null} { "interactions": [ { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "createdAt": 1785228932000, "externalCreatedAt": 1785228931000, "source": "widget", "channel": "chat", "status": "resolved", "externalId": "widget-conversation-4821", "url": null, "subjectPreview": "Refund eligibility", "hasFeedback": false, "resolved": true, "userAttributes": { "plan": "Pro" }, "usedArticles": [ { "id": "fd88d59f-4dd5-4922-a872-6bdd0be20e55", "title": "Refund policy", "documentUrl": "https://help.example.com/refunds" } ], "usedSubfolders": [ { "id": "60430f95-ddf8-4105-996a-203aa28dd66f", "title": "Billing" } ], "events": [ { "id": "5243cbb1-b744-4a60-8062-857bb014acba", "interactionId": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "createdAt": 1785228932000, "role": "user", "type": "message", "message": "Can I get a refund for last month's charge?", "externalId": "message-104", "externalCreatedAt": 1785228931000, "csatRating": null, "feedback": null, "approved": null, "resolved": null, "attachments": [ { "gcpUrl": "https://storage.googleapis.com/example-public/receipt.pdf", "gcpPath": "receipts/receipt.pdf", "originalUrl": "https://files.example.com/receipt.pdf", "contentType": "application/pdf", "expiresAt": 1785315332000, "sizeBytes": 48321 } ], "tags": [ { "id": "b08ee98d-f987-48c9-8f19-8fc12c6f8a0b", "name": "Refund request", "groupId": "c827a4bd-b32a-474a-af86-b2f24190f39a" } ], "usedArticles": [ { "id": "fd88d59f-4dd5-4922-a872-6bdd0be20e55", "title": "Refund policy", "documentUrl": "https://help.example.com/refunds" } ] }, { "id": "c5df46c8-4d6f-468c-a8bf-bc2e59ea1249", "interactionId": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "createdAt": 1785228940000, "role": "finibot", "type": "message", "message": "Refunds are available within 30 days.", "externalId": "message-105", "externalCreatedAt": 1785228940000, "csatRating": null, "feedback": null, "approved": null, "resolved": null, "attachments": [ { "gcpUrl": "https://storage.googleapis.com/example-public/policy.pdf", "gcpPath": "policies/refund-policy.pdf", "originalUrl": "https://help.example.com/refund-policy.pdf", "contentType": "application/pdf", "expiresAt": 1785315340000, "sizeBytes": 93214 } ], "tags": [ { "id": "b08ee98d-f987-48c9-8f19-8fc12c6f8a0b", "name": "Refund request", "groupId": "c827a4bd-b32a-474a-af86-b2f24190f39a" } ], "usedArticles": [ { "id": "fd88d59f-4dd5-4922-a872-6bdd0be20e55", "title": "Refund policy", "documentUrl": "https://help.example.com/refunds" } ] } ] } ], "hasMore": false, "nextCursor": null, "prevCursor": null } ``` The `400 Bad Request` `message` varies by cause. It may quote the specific rule that failed (`since`/`until` range > 90 days, `since >= until`, invalid UUID, etc.). See [Errors](#errors) for the full list of causes. ## Field semantics ### Conversation timestamps `createdAt` is the Fini ingestion timestamp: when Fini created the stored conversation record. The `since` and `until` query parameters filter this field. `externalCreatedAt` is the timestamp reported by the source provider for the conversation. It is `null` when the source does not provide one. Use it to place delayed or backfilled conversations on the provider's original timeline after retrieving them by their Fini ingestion window. Events follow the same distinction. `events[].createdAt` is when Fini stored the event, while `events[].externalCreatedAt` is the provider-side timestamp for that specific event when available. ### userAttributes `userAttributes` is an open-ended object. Fini returns the attributes captured on the conversation as-is, so the schema is **consumer-defined** and can vary by workspace. If your bots populate CRM-specific or workflow-specific fields, they appear here unchanged. ### csatRating `events[].csatRating` is passed through from the stored event data: * `null` means no CSAT value is present on that event * numeric values are returned as stored If your upstream data writes `0`, the API returns `0`. Do **not** automatically treat `0` as "unrated" unless that is how your own channel or integration encodes the value. ### Event roles `events[].role` can currently be: | Value | Meaning | | ---------- | ---------------------------------------------------------------- | | `user` | A message from the end user or customer. | | `agent` | A human agent message synced from the connected provider. | | `finibot` | A Fini-generated message or system action. | | `otherbot` | A non-Fini bot or automation message from the upstream provider. | ### Event types `events[].type` can currently be: | Value | Meaning | | ------------------- | --------------------------------------------------------------- | | `message` | A normal message event. | | `internalnote` | A private/internal note rather than a customer-visible message. | | `no_reply` | Fini decided not to send a reply. | | `silent_escalation` | Fini escalated without posting a visible reply. | | `debounce` | A debounce/system event used internally around message timing. | | `widget_form` | A widget form conversation event. | ## Nested objects | Field | Type | Description | | ------------------- | ------------------- | -------------------------------------------------------------------------------------- | | `id` | string | Conversation ID. Also used as the pagination cursor. | | `createdAt` | epoch ms | Fini ingestion timestamp. The `since` and `until` parameters filter this field. | | `externalCreatedAt` | epoch ms \| null | Provider-side conversation timestamp when available. | | `source` | string | Source of the conversation, such as `api`, `widget`, `ui`, or a connected integration. | | `channel` | string | Channel type. Currently `email` or `chat`. | | `status` | string \| null | Human-readable conversation status, if available. | | `externalId` | string \| null | External system identifier when the conversation came from an integration. | | `url` | string \| null | Link back to the source conversation, when available. | | `subjectPreview` | string \| null | Short subject or preview string for the conversation. | | `hasFeedback` | boolean | Whether the conversation has feedback attached. | | `resolved` | boolean \| null | Whether the conversation has been marked resolved. | | `userAttributes` | object \| null | User attributes captured on the conversation. See [Field semantics](#userattributes). | | `usedArticles` | `PublicArticle[]` | Public article references used during the conversation. | | `usedSubfolders` | `PublicSubfolder[]` | Public subfolder references used during the conversation. | | `events` | `PublicEvent[]` | Chronological event stream for the conversation. | | Field | Type | Description | | ------------------------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Event ID. | | `interactionId` | string | Conversation ID that owns the event. | | `createdAt` | epoch ms | When Fini stored the event. | | `role` | string | One of the event roles documented above. | | `type` | string | One of the event types documented above. | | `message` | string \| null | Message text, when the event carries message content. | | `externalId` | string \| null | Provider-side message ID when available. | | `externalCreatedAt` | epoch ms \| null | Provider-side timestamp when available. | | `csatRating` | number \| null | Numeric CSAT value if one was stored on the event. | | `feedback` | string \| null | Free-text feedback note attached to the event. | | `approved` | boolean \| null | Thumbs up (`true`), thumbs down (`false`), or unrated (`null`). | | `resolved` | boolean \| null | Resolution flag for negatively rated or flagged events. | | `attachments` | array | File attachments on the event. Passed through from stored event data; commonly includes fields like `originalUrl`, `contentType`, `expiresAt`, `sizeBytes`, and storage URLs. | | `tags` | `PublicTag[]` | Tags attached to the event. | | `usedArticles` | `PublicArticle[]` | Articles retrieved for that specific event. | | `executedUserAttributes` | `UserAttributeExecution[]` \| null | User-attribute tools executed for the event. Optional when execution metadata was not recorded. | | `executedRuleResults` | `RuleNodeExecution[]` \| null | Rule nodes executed for the event. Optional when rule execution metadata was not recorded. | | Field | Type | Description | | --------------- | ---------------------------- | -------------------------------------------------------------- | | `id` | string | User-attribute tool ID. | | `name` | string | Tool name. | | `success` | boolean | Whether the tool completed successfully. | | `extractedData` | object | Attribute values extracted by the tool. | | `results` | `ExposedFunctionExecution[]` | Optional results from API-function steps executed by the tool. | | Field | Type | Description | | --------- | ------- | -------------------------------------------- | | `id` | string | Optional API-function configuration ID. | | `name` | string | API-function step name. | | `success` | boolean | Whether the step completed successfully. | | `error` | string | Optional error message when the step failed. | | Field | Type | Description | | -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | Rule node ID. | | `name` | string | Rule node name. | | `type` | string | Node type: `SEQUENCE`, `SELECTOR`, `ACTION`, `CONDITION`, or `WIDGET_FORM_RENDERER`. | | `success` | boolean | Whether the node completed successfully. | | `subType` | string | Optional action subtype: `LLM_EXTRACTION`, `TOOL_CALL`, `PROMPT_INJECTION`, `WIDGET_FORM_VALIDATION_ERROR`, or `SEND_MESSAGE`. | | `terminate` | boolean | Optional flag indicating that rule execution terminated at this node. | | `result` | any | Optional node-specific result payload. | | `toolResult` | `RuleToolExecution` | Optional tool execution details for action nodes. | | `overrideMainPrompt` | boolean | Optional flag indicating that the node overrides the main prompt. | | `systemFields` | object | Optional system output. May contain `ticketId`, `ticketNumber`, `ticketUrl`, and boolean `escalationActive` fields. | | Field | Type | Description | | -------------------- | --------------------- | -------------------------------------------------------- | | `id` | string | Tool ID. | | `name` | string | Tool name. | | `success` | boolean | Whether the tool completed successfully. | | `extractedData` | object | Values extracted by the tool. | | `attributeLlmPolicy` | object | Map of attribute names to boolean LLM-exposure policies. | | `results` | `FunctionExecution[]` | Optional API-function step results. | | Field | Type | Description | | ----------------- | ------- | -------------------------------------------- | | `id` | string | Optional API-function configuration ID. | | `name` | string | API-function step name. | | `stepNumber` | number | Execution order of the API-function step. | | `success` | boolean | Whether the step completed successfully. | | `resolvedUrl` | string | Optional resolved request URL. | | `resolvedHeaders` | any | Optional resolved request headers. | | `resolvedBody` | any | Optional resolved request body. | | `data` | any | Optional response data. | | `error` | string | Optional execution error. | | `extractedData` | object | Optional values extracted from the response. | | Field | Type | Description | | ------------- | -------------- | ----------------------------------- | | `id` | string | Article ID. | | `title` | string | Article title. | | `documentUrl` | string \| null | Source document URL when available. | | Field | Type | Description | | ------- | ------ | ------------- | | `id` | string | Folder ID. | | `title` | string | Folder title. | | Field | Type | Description | | --------- | -------------- | ------------------------------------ | | `id` | string | Tag ID. | | `name` | string | Tag name. | | `groupId` | string \| null | Parent tag-group ID when one exists. | ## Pagination Cursor pagination is relative to the current cursor, not to time: * pass `nextCursor` with `direction=next` to move to **older** conversations * pass `prevCursor` with `direction=previous` to move back toward **newer** conversations If you omit `cursor`, the API starts from the newest matching conversations in the requested time window. ## Errors The query parameters are invalid. Common causes: an invalid UUID, `since` later than or equal to `until`, or a time window larger than 90 days. The response `message` quotes the specific rule that failed. The API key is missing, malformed, revoked, or invalid. Confirm you are sending `Authorization: Bearer fini_...` with the full key. The API key does not include the `read` scope required for this route. You exceeded the rate limit. Back off and retry with your own client-side policy. See [Rate limits](#rate-limits). Fini failed to fulfill the request. Retry once, then contact support if the error persists. ## Rate limits The API applies a global throttle of **100 requests per 60 seconds**. Two caveats: * this endpoint does not currently document `X-RateLimit-*` headers * this endpoint does not currently document a `Retry-After` header contract If you receive `429`, back off and retry with your own client-side policy. # List default Business Rules Source: https://docs.usefini.com/en/api-reference/list-default-rules GET https://api-prod.usefini.com/v2/hc-rules/default/public List Fini-provided Business Rule templates. Returns Fini-provided Business Rule templates as summary objects. Use a template's `id` as `defaultRuleId` when creating a template-based rule. This endpoint supports Business Rules only. The repository filters default templates to `type=business`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Optional source filter. The current enum value is `widget`. ## Response Returns an array of [`Rule summary`](/en/api-reference/rules#rule-summary-object) objects without `flowConfig`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/hc-rules/default/public?source=web' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/default/public?source=web', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/hc-rules/default/public?source=web", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 200 OK theme={null} [ { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` Default templates have `companyId: null`. A workspace rule created from a template references it through `defaultRuleId` and cannot provide its own `flowConfig`. ## Errors `source` is not a supported rule source. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading default rules. # List provider resources Source: https://docs.usefini.com/en/api-reference/list-provider-resources GET https://api-prod.usefini.com/v2/documents/public/resources/{provider} Discover importable resources from a connected provider. Step 1 of the provider import flow. Lists resources that can be imported from a connected provider. This is the first call in the connected-source flow. Once you have picked the resources you want, pass them to [Register provider resources](/en/api-reference/register-provider-resources) to create source records. Resources that have already been imported successfully from the provider are excluded from the response. This endpoint is for discovering *new* content, not auditing what is already in Fini. To see what is already imported, use [List sources](/en/api-reference/list-sources) with the provider as a `source` filter. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Provider name. Supported values: `notion`, `zendesk`, `confluence`. The provider must already be connected in the workspace via the dashboard. A disconnected or unsupported provider returns `400 Bad Request`. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/documents/public/resources/notion' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests provider = "notion" response = requests.get( f"https://api-prod.usefini.com/v2/documents/public/resources/{provider}", headers={"Authorization": "Bearer fini_your_api_key"}, ) resources = response.json() ``` ```javascript Node.js theme={null} const provider = "notion"; const response = await fetch( `https://api-prod.usefini.com/v2/documents/public/resources/${provider}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const resources = await response.json(); ``` ## Response The response shape varies by provider. ### Notion A flat array of `NotionResource` objects. Array of importable Notion resources. ### Zendesk A nested category tree returned as `ZendeskCategory[]`. Categories contain section `children`, and sections contain article `children`. Root category tree for the connected Zendesk help center. ### Confluence An array of `ConfluenceSpace` objects, each with nested `pages`. Array of importable Confluence spaces. ```json Notion theme={null} [ { "externalId": "123456", "title": "Billing FAQ", "originalUrl": "https://www.notion.so/fini/Billing-FAQ-123456", "mimeType": "text/markdown", "iconLink": null, "object": "page" }, { "externalId": "789012", "title": "Refund Policy", "originalUrl": "https://www.notion.so/fini/Refund-Policy-789012", "mimeType": "text/markdown", "iconLink": "https://www.notion.so/icons/document_gray.svg", "object": "page" } ] ``` ```json Zendesk theme={null} [ { "externalId": "200001", "title": "Billing", "type": "category", "children": [ { "externalId": "300001", "title": "Payments", "type": "section", "children": [ { "externalId": "400001", "title": "How do I update my card?", "originalUrl": "https://example.zendesk.com/hc/en-us/articles/400001", "type": "article" } ] } ] } ] ``` ```json Confluence theme={null} [ { "key": "SUPPORT", "title": "Support Space", "originalUrl": "https://example.atlassian.net/wiki/spaces/SUPPORT", "pages": [ { "externalId": "98765", "title": "Troubleshooting login issues", "originalUrl": "https://example.atlassian.net/wiki/spaces/SUPPORT/pages/98765" } ] } ] ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": "Provider not supported on public route", "error": "Bad Request" } ``` ## Nested objects ### NotionResource Notion page or database ID. Resource title. Notion URL. MIME type. Typically `text/markdown` for pages. URL to the resource's Notion icon, when set. Notion object type, for example `page` or `database`. ### ZendeskCategory Zendesk category ID. Category title. Always `category`. Nested sections inside the category. ### ZendeskSection Zendesk section ID. Section title. Always `section`. Nested articles inside the section. ### ZendeskArticle Zendesk article ID. Article title. Zendesk article URL. Always `article`. ### ConfluenceSpace Confluence space key. Space title. Space URL. Pages discovered inside the space. ### ConfluencePage Confluence page ID. Page title. Page URL. ## Next step Once you've picked the resources to import, pass them to [Register provider resources](/en/api-reference/register-provider-resources) to create source records. Resource registration alone does **not** queue ingestion. You still need to call [Ingest sources](/en/api-reference/ingest-sources) after. ## Errors The provider is not supported on the public route (only `notion`, `zendesk`, `confluence` are accepted), or it's not connected in the workspace yet. Connect the provider in the dashboard first. The API key is missing, malformed, revoked, or invalid. Confirm `Authorization: Bearer fini_...` with the full key. The API key doesn't include the `read` scope, or the provider connection belongs to a different workspace. Either the provider has no content to import, or everything available has already been imported. Already-imported resources are filtered out. Check [List sources](/en/api-reference/list-sources) with `source` set to the provider to see what is already in Fini. # List replays Source: https://docs.usefini.com/en/api-reference/list-replays GET https://api-prod.usefini.com/v2/replays/interactions/{interactionId}/public List replay conversations created from one original conversation. Returns replay conversations created from one original conversation. Use this after [Create replay](/en/api-reference/create-replay) when you want to compare all replay attempts for the same source conversation. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Original conversation ID whose replays you want to list. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/replays/interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests interaction_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.get( f"https://api-prod.usefini.com/v2/replays/interactions/{interaction_id}/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) replays = response.json() ``` ```javascript Node.js theme={null} const interactionId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/replays/interactions/${interactionId}/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const replays = await response.json(); ``` ## Response Number of replay conversations returned. Replay conversation records. Each item is an interaction object with `parentInteractionId` pointing back to the original conversation and `replay` metadata describing the target event and replay status. ```json 200 OK theme={null} { "total": 1, "replays": [ { "id": "9d4bbcf7-e7e1-44a6-9a64-ff0a12dfe625", "companyId": "6bc9f4f8-3564-4a9c-8cc0-ea1f1dd66c2d", "botId": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "source": "replay", "channel": "widget", "status": "resolved", "createdAt": "2026-07-30T12:18:03.211Z", "updatedAt": "2026-07-30T12:18:14.904Z", "parentInteractionId": "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8", "replay": { "target_event_id": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "status": "done" } } ] } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading replay conversations for the original conversation. # List sources Source: https://docs.usefini.com/en/api-reference/list-sources GET https://api-prod.usefini.com/v2/documents/public Paginate through every source record in the workspace, with filters on source type, ingestion status, linked knowledge, hostname, and more. Returns source records in the workspace tied to your API key, ordered by `updatedAt` descending then `externalId` descending by default. Set `order=asc` to reverse the order. Use it to enumerate sources, inspect ingestion status, and find source IDs to pass back to [Ingest sources](/en/api-reference/ingest-sources). For the end-to-end model, see [Sources](/en/api-reference/sources). For async polling guidance, see [Ingest sources](/en/api-reference/ingest-sources#polling-for-completion). The response field is still named `documents` because that is the current API contract. On this page, each entry is described as a source record. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters Maximum number of source records to return. Source ID to paginate from. Use the last source's `id` from the previous response to fetch the next page, or the first source's `id` to fetch the previous page. Pagination direction when a cursor is supplied. **Note the inverted mapping:** `next` moves toward *older* sources; `previous` moves back toward *newer* ones. This is because results are sorted by `updatedAt` descending. Sort direction for `updatedAt`, followed by `externalId`. Accepted values: `asc`, `desc`. Optional source-type filter. Supported values: `web`, `files`, `googledrive`, `zendesk`, `notion`, `confluence`. Optional English-processing filter. Filter by ingestion outcome. Pass `true` for successful sources or `false` for failed sources. This is an array-valued query parameter. Exact source ID filter. Case-insensitive partial match on the source title. Case-insensitive partial match on the original source URL. Filter web sources by exact hostname, for example `docs.example.com`. This parameter is valid only when `source=web`. Filter by linked article or knowledge node ID. Pass `true` to return sources linked to a knowledge article or `false` to return sources without one. Supplying both values disables this filter. Filter by linked knowledge operation. Supported values: `ADD_ARTICLE_TO_FOLDER`, `UPDATE_ARTICLE`, `DO_NOTHING`. Return only linked sources flagged as changed. This is the key filter for the source-refresh workflow before [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge). The response includes `hasMore` but not a `nextCursor` field. Use the last or first source `id` from the returned array as the cursor for the next call. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/documents/public?limit=25&source=notion' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/documents/public", headers={"Authorization": "Bearer fini_your_api_key"}, params={ "limit": 25, "source": "notion", }, ) data = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams({ limit: "25", source: "notion", }); const response = await fetch( `https://api-prod.usefini.com/v2/documents/public?${params.toString()}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const data = await response.json(); ``` ## Response Array of `Document` objects. Whether more results exist beyond the current page. ```json 200 OK theme={null} [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "source": "web", "url": "https://help.example.com/refunds", "title": "Refund policy", "success": true, "changed": false, "linkedJobStatus": "COMPLETED", "linkedKnowledgeId": "7fa27325-e2f6-4420-b705-436f9106f908", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] ``` ## Nested objects ### Document `Document` is the wire-format object returned by the sources read routes. In the product model, each `Document` is one source record. Source ID. Also used as the pagination cursor. Original provider URL or web link. Source title. Internal storage URL when the source has been uploaded into Fini's storage layer. ID of the workspace that owns the source. Source type. One of `web`, `files`, `googledrive`, `notion`, `zendesk`, or `confluence`. Provider-specific external identifier, or the URL itself for `web`. Whether English processing is enabled for the source. Whether BASER processing is enabled for the source. Whether the latest ingestion or refresh run succeeded. Latest processing error, if any. Empty string when the last run succeeded. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Used as the sort key. Source MIME type. Provider-specific type, when available, for example Notion `page`. Linked article or knowledge node ID, if this source has already been turned into knowledge. Operation used when the source last linked into knowledge. One of `ADD_ARTICLE_TO_FOLDER`, `UPDATE_ARTICLE`, `DO_NOTHING`. Additional reason metadata for the linked operation, when present. Background job ID for the latest queued ingest or refresh. Background job status. One of `PENDING`, `IN_PROGRESS`, `COMPLETED`, `FAILED`. Whether the latest refresh detected a meaningful change compared with the previously linked content. This is the key field for the source-refresh workflow. Extracted paragraph payload, if the source has been processed. Can be large. Use [Get source](/en/api-reference/get-source) when you need one source and want a focused payload. Previous paragraph snapshot used for change detection, when available. ## Pagination Cursor pagination uses source IDs directly: * pass the **last** source's `id` from the previous response with `direction=next` to move toward **older** sources * pass the **first** source's `id` with `direction=previous` to move back toward **newer** sources If you omit `cursor`, the API starts from the most recently updated sources. ## Errors Query parameters are invalid. Common causes: unsupported `source` value, unsupported `linkedOperation` value, malformed UUID in `id` or `articleId`. The API key is missing, malformed, revoked, or invalid. Confirm `Authorization: Bearer fini_...` with the full key. The API key doesn't include the `read` scope, or it's scoped to a different workspace. Either the workspace has no sources matching your filters, or no sources at all. Drop filters one at a time to confirm which one is excluding results. # List tag groups Source: https://docs.usefini.com/en/api-reference/list-tag-groups GET https://api-prod.usefini.com/v2/tag-groups/public List the tag groups visible to your workspace API key, including Fini defaults and workspace-owned custom groups. Returns every tag group visible to the workspace API key, ordered by `createdAt` descending. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/tag-groups/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/tag-groups/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) tag_groups = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/tag-groups/public", { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const tagGroups = await response.json(); ``` ## Response The response is a top-level array of [`TagGroup`](/en/api-reference/tag-groups#taggroup-object) objects. ```json 200 OK theme={null} [ { "id": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "createdAt": "2026-06-12T10:14:22.000Z", "companyId": "38ba4db0-31db-4669-bb95-7b8313c4016b", "title": "Order Intent", "description": "Primary order-related intent used for routing and reporting.", "prompt": "Choose the single tag that best describes the customer's order request.", "multiselect": false, "updatedAt": "2026-06-12T10:14:22.000Z", "mandatory": false, "isOutputTagGroup": false }, { "id": "a7f8e849-0a1c-4d95-a311-0cb1ffbe4b4d", "createdAt": "2026-05-01T08:00:00.000Z", "companyId": null, "title": "Conversation Status", "description": "Tracks the final state of the conversation.", "prompt": "Select the final conversation state based on the assistant's most recent handling outcome.", "multiselect": false, "updatedAt": "2026-05-01T08:00:00.000Z", "mandatory": true, "isOutputTagGroup": false } ] ``` ```json 401 Unauthorized theme={null} { "statusCode": 401, "message": "Invalid or revoked API key", "error": "Unauthorized" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ``` ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading tag groups from storage. # List tags across groups Source: https://docs.usefini.com/en/api-reference/list-tags-across-groups GET https://api-prod.usefini.com/v2/tag-groups/tags/public List tags across one or more tag groups as a flat array. Lists tags across one or more tag groups as a single flat array, ordered by `createdAt` descending. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Query parameters One or more tag group IDs. Pass repeated query params such as `?tagGroupIds=id1&tagGroupIds=id2`. This route does not accept a comma-separated CSV string. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/tag-groups/tags/public?tagGroupIds=4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5&tagGroupIds=f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/tag-groups/tags/public", headers={"Authorization": "Bearer fini_your_api_key"}, params=[ ("tagGroupIds", "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5"), ("tagGroupIds", "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5"), ], ) tags = response.json() ``` ```javascript Node.js theme={null} const params = new URLSearchParams(); params.append("tagGroupIds", "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5"); params.append("tagGroupIds", "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5"); const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/tags/public?${params.toString()}`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const tags = await response.json(); ``` ## Response The response is a top-level array of [`Tag`](/en/api-reference/tags#tag-object) objects. The response is not grouped by `tagGroupId`; if you need grouped data, regroup the flat array client-side. ```json 200 OK theme={null} [ { "id": "0dc53764-a417-4a4f-b7f4-63149529f530", "createdAt": "2026-06-19T07:32:10.000Z", "tagGroupId": "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5", "tagName": "resolved_by_ai", "tagDescription": "Use when the assistant fully resolved the request." }, { "id": "2bd5626c-2122-478c-9c34-94fcf2d2cccb", "createdAt": "2026-06-12T10:17:02.000Z", "tagGroupId": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "tagName": "Cancel Order", "tagDescription": "Use when the customer wants to cancel an existing order." } ] ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": "Invalid tag group ID. Some groups do not exist or do not belong to your company.", "error": "Bad Request" } ``` ## Errors `tagGroupIds` is missing, malformed, or includes one or more IDs the controller rejects. The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading tags from storage. # List tags in group Source: https://docs.usefini.com/en/api-reference/list-tags-in-group GET https://api-prod.usefini.com/v2/tag-groups/{id}/tags/public List the tags inside one tag group. Lists the [`Tag`](/en/api-reference/tags#tag-object) objects in one tag group, ordered by `createdAt` descending. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Tag group ID whose tags you want to list. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/tag-groups/4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5/tags/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```python Python theme={null} import requests tag_group_id = "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5" response = requests.get( f"https://api-prod.usefini.com/v2/tag-groups/{tag_group_id}/tags/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) tags = response.json() ``` ```javascript Node.js theme={null} const tagGroupId = "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/${tagGroupId}/tags/public`, { headers: { Authorization: "Bearer fini_your_api_key", }, } ); const tags = await response.json(); ``` ## Response The response is a top-level array of [`Tag`](/en/api-reference/tags#tag-object) objects. ```json 200 OK theme={null} [ { "id": "2bd5626c-2122-478c-9c34-94fcf2d2cccb", "createdAt": "2026-06-12T10:17:02.000Z", "tagGroupId": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "tagName": "Cancel Order", "tagDescription": "Use when the customer wants to cancel an existing order." }, { "id": "76f90f08-7857-4853-bc17-2f1487516a3d", "createdAt": "2026-06-12T10:16:00.000Z", "tagGroupId": "4fbcebbd-693d-4fb8-84b2-c8fd0edee4c5", "tagName": "Track Order", "tagDescription": "Use when the customer is asking where an existing order is." } ] ``` Current controller behavior: unknown tag group IDs currently surface as `500 Internal Server Error` on this public route rather than a dedicated `404 Not Found`. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope required for this route. Fini failed while loading the group or its tags. Unknown tag group IDs currently surface here as well. # List runs Source: https://docs.usefini.com/en/api-reference/list-test-set-runs GET https://api-prod.usefini.com/v2/test-sets/{testSetId}/runs/public List run summaries for one test set. Returns paginated run summaries for one test set, newest first. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Path parameters Test set ID. ## Query parameters Number of runs to return. Minimum `1`, maximum `100`. Number of runs to skip. ## Response Returns an array of [Run objects](/en/api-reference/test-sets#run-object). ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/runs/public?limit=25&offset=0' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const params = new URLSearchParams({ limit: '25', offset: '0' }); const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/runs/public?${params}`, { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const runs = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.get( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/runs/public", headers={"Authorization": "Bearer fini_your_api_key"}, params={"limit": 25, "offset": 0}, ) runs = response.json() ``` ```json 200 OK theme={null} [ { "id": "5afd818a-a5f9-4e1b-9619-3c7191c12d9a", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "status": "completed", "result": { "summary": { "testSetResult": "pass", "totalConversations": 2, "passedConversations": 2, "failedConversations": 0, "errorConversations": 0, "totalCriteria": 2, "passedCriteria": 4, "failedCriteria": 0 }, "conversations": [ { "hcInteractionId": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "result": "pass", "error": null, "criteriaResults": [ { "criteriaId": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "name": "Goal resolution", "type": "complex_judge", "blocking": true, "result": "pass", "reasoning": "The answer resolved the refund-policy question.", "evidence": ["The agent explained eligibility and next steps."] } ] } ] }, "createdBy": null, "createdAt": "2026-07-28T09:01:14.000Z", "updatedAt": "2026-07-28T09:02:09.000Z" } ] ``` # List test sets Source: https://docs.usefini.com/en/api-reference/list-test-sets GET https://api-prod.usefini.com/v2/test-sets/public List all Test Suite regression sets in the workspace. Returns all test sets in the workspace, newest first. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. ## Response Returns an array of test set summaries. List responses include `conversationCount` and `criteriaCount` instead of the full `conversationIds` array. ```bash cURL theme={null} curl --request GET \ --url 'https://api-prod.usefini.com/v2/test-sets/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/test-sets/public', { method: 'GET', headers: { Authorization: 'Bearer fini_your_api_key' } }); const testSets = await response.json(); ``` ```python Python theme={null} import requests response = requests.get( "https://api-prod.usefini.com/v2/test-sets/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) test_sets = response.json() ``` ```json 200 OK theme={null} [ { "id": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "name": "Refund regression set", "description": "Refund-policy conversations to re-check before prompt changes.", "conversationCount": 12, "criteriaCount": 2, "createdBy": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T08:55:32.000Z" } ] ``` # Overview Source: https://docs.usefini.com/en/api-reference/manage-knowledge Section hub for reading, creating, updating, drafting, publishing, and deleting articles. These routes manage articles directly in Fini's live knowledge graph. Use this section when you already know the article content you want to store or update directly. For source-backed generation, start from [Knowledge](/en/api-reference/knowledge) and the generation routes there. ## Reference pages `GET /v2/hc-articles/public` — list live articles, draft articles, or both. `POST /v2/hc-articles/ids/public` — fetch one or more articles by ID. `POST /v2/hc-articles/public` — create a live article or draft article. `PUT /v2/hc-articles/:id/public` — update an existing article. `POST /v2/hc-articles/:id/draft/public` — create a draft from an existing article. `POST /v2/hc-articles/:id/publish/public` — publish a draft article. `DELETE /v2/hc-articles/:id/public` — delete an article. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | ------------------------------------ | ------- | --------------------------------------------------------- | | `GET` | `/v2/hc-articles/public` | `read` | List articles. Use `type=live` or `type=draft` to filter. | | `POST` | `/v2/hc-articles/ids/public` | `read` | Fetch one or more articles by ID. | | `POST` | `/v2/hc-articles/public` | `write` | Create a live article or draft article. | | `PUT` | `/v2/hc-articles/:id/public` | `write` | Update an existing article. | | `POST` | `/v2/hc-articles/:id/draft/public` | `write` | Create a draft from an existing article. | | `POST` | `/v2/hc-articles/:id/publish/public` | `write` | Publish a draft article. | | `DELETE` | `/v2/hc-articles/:id/public` | `write` | Delete an article. | There is no workspace-API-key `GET /v2/hc-articles/:id/public` route in the current controller. If you want to fetch by ID, use `POST /v2/hc-articles/ids/public` with one or more `articleIds`. ## Article object Article ID. Article title. Main knowledge body. Additional instructions the agent should apply when using this article. Question prompts associated with the article. Keyword list associated with the article. Whether the article is marked as escalation-related. Internal metadata stored with the article. Source-backed generation and draft flows may use this to retain linkage data. Whether the article is active. Whether the article is public in the help center. Folder that contains the article. Workspace ID that owns the article. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Article version, when versioning metadata is available. Whether the draft has already been published, when applicable. Original live article ID when this object is a draft of an existing article. Version of the original live article when this draft was created. User ID that created the article, when stored. Origin marker for the article, when one was stored. Use the child pages in this section for the detailed request and response reference for each route. # Move article Source: https://docs.usefini.com/en/api-reference/move-article PUT https://api-prod.usefini.com/v2/hc-articles/{id}/move/public Move an article into a different folder. Use this route to move an article between folders in the knowledge tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Article ID to move. ## Body parameters Destination folder ID. ## Response Returns the moved article object. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public', { method: 'PUT', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'parentFolderId': '0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.put( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` The response reflects the article after its `parentFolderId` has been updated. ## Errors The request body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The article or destination folder does not exist in the workspace. # Move knowledge folder Source: https://docs.usefini.com/en/api-reference/move-knowledge-folder PUT https://api-prod.usefini.com/v2/hc-folders/{id}/move/public Move a folder under a different parent in the knowledge tree. Use this route to change where a folder sits in the tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Folder ID to move. ## Body parameters Destination parent folder ID. ## Response Returns the moved knowledge folder object. See [Organize knowledge](/en/api-reference/organize-knowledge) for the shared folder fields. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public', { method: 'PUT', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'parentFolderId': '0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.put( "https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/move/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b" }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` The response reflects the folder after its `parentFolderId` has been updated. ## Errors The request body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The folder does not exist, the destination parent folder does not exist, or the requested tree change is not allowed. # Overview Source: https://docs.usefini.com/en/api-reference/organize-knowledge Section hub for reading knowledge folders, managing folders, moving articles, and assigning knowledge to agents. Knowledge folders are the structural layer of Fini's live knowledge graph. Use these routes to inspect the current folder structure, manage folders, move articles between folders, and decide which agents can use that knowledge. Folders organize articles. They are not a second source of truth. The article content inside those folders is still what the agent retrieves from. ## Reference pages `GET /v2/hc-folders/public` — return the current tree snapshot, optionally scoped to one agent. `POST /v2/hc-folders/public` — create a folder in the tree. `PUT /v2/hc-folders/:id/public` — update a folder's title, description, or active state. `PUT /v2/hc-folders/:id/move/public` — move a folder under a different parent. `PUT /v2/hc-articles/:id/move/public` — move an article into a different folder. `DELETE /v2/hc-folders/:id/public` — delete a folder from the tree. `POST /v2/hc-bot-folder-junctions/public` — assign or unassign folders to agents in bulk. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | ------------------------------------ | ------- | --------------------------------------------------------------------------- | | `GET` | `/v2/hc-folders/public` | `read` | Return the current knowledge-tree snapshot, optionally scoped to one agent. | | `POST` | `/v2/hc-folders/public` | `write` | Create a folder in the knowledge tree. | | `PUT` | `/v2/hc-folders/:id/public` | `write` | Update a folder's title, description, or active state. | | `PUT` | `/v2/hc-folders/:id/move/public` | `write` | Move a folder under a different parent. | | `PUT` | `/v2/hc-articles/:id/move/public` | `write` | Move an article into a different folder. | | `DELETE` | `/v2/hc-folders/:id/public` | `write` | Delete a folder from the tree. | | `POST` | `/v2/hc-bot-folder-junctions/public` | `write` | Assign or unassign folders to agents in bulk. | ## Knowledge folders snapshot object Snapshot ID. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Nested folder-and-article tree for the workspace. When `botId` is supplied, this array is filtered to the folders assigned to that agent. The workspace-API-key response for `GET /v2/hc-folders/public` does not include `companyId` or `publicSnapshotV2`, even though those fields exist on the stored snapshot internally. ## Folder object Folder ID. Workspace ID that owns the folder. Parent folder ID. `null` or empty for a top-level folder. Folder title. Folder description. Internal metadata object for the folder. Whether the folder is active. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Use the child pages in this section for the detailed request and response reference for each route. # Persist knowledge folders Source: https://docs.usefini.com/en/api-reference/persist-knowledge-folders POST https://api-prod.usefini.com/v2/knowledge/public/tree/persist Upload a tree file and persist it into the workspace knowledge graph. Use this route to import a tree file that you generated with [Initialize knowledge folders](/en/api-reference/initialize-knowledge-folders) or edited before upload. Send the file as `multipart/form-data` with the form field name `file`. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `multipart/form-data` ## Body parameters Tree file generated from the initialize route or edited by your team before import. ## Response Import status string. Human-readable import message. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/knowledge/public/tree/persist' \ --header 'Authorization: Bearer fini_your_api_key' \ --form 'file=@fini-tree-template.csv' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/knowledge/public/tree/persist', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'file': 'knowledge-tree.csv' } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/knowledge/public/tree/persist", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "file": "knowledge-tree.csv" }, ) data = response.json() ``` ```json 200 OK theme={null} { "folders": [ { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ], "articles": [ { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ] } ``` ## Errors The request is malformed or the `file` field is missing from the multipart payload. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. Fini failed while persisting the uploaded tree file. Retry once, then validate the file format before trying again. # Publish article draft Source: https://docs.usefini.com/en/api-reference/publish-article-draft POST https://api-prod.usefini.com/v2/hc-articles/{id}/publish/public Publish a draft article. Use this route to publish a draft article into the live knowledge graph. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Draft article ID to publish. ## Body parameters This route uses the same required content fields as [Create article](/en/api-reference/create-article). `active`, `public`, and `origin` are also accepted here. ## Response Returns the live article that remains after publish. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key' } }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/publish/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` If the draft was created from an existing live article, the response is that updated original live article. Otherwise, the response is a newly created live article. ## Errors The request body is malformed or one of the required arrays is empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The draft article does not exist in the workspace. # Overview Source: https://docs.usefini.com/en/api-reference/refine-with-ai Queue Refine with AI iterations, poll their progress, and inspect proposed answer improvements through Fini's public API. Refine with AI lets your backend queue an AI-assisted review for a specific Fini response, then poll the review session until Fini has generated recommendations and replayed the answer. Use these routes when you already have the conversation ID and Fini-authored event ID for the response you want to improve. Use [List conversations](/en/api-reference/list-conversations) or [Get conversation](/en/api-reference/get-conversation) to discover those IDs first. Creating a review iteration can generate draft prompt, article, or rule recommendations. It does not publish or apply those changes automatically. ## Endpoints | Method | Path | Scope | Reference | | ------ | ---------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------ | | `POST` | `/v2/fix-review/interactions/:id/events/:eventId/sessions/iterations/public` | `write` | [Create Refine with AI iteration](/en/api-reference/create-fix-review-iteration) | | `GET` | `/v2/fix-review/interactions/:id/events/:eventId/session/public` | `read` | [Get active Refine with AI session](/en/api-reference/get-active-fix-review-session) | | `GET` | `/v2/fix-review/interactions/:id/events/:eventId/sessions/:sessionId/public` | `read` | [Get Refine with AI session](/en/api-reference/get-fix-review-session) | ## Review flow Fetch the conversation and choose the Fini-authored event you want to review. Send the feedback note to the create endpoint. Fini creates or reuses the active review session for that response. Use the returned `sessionId`, or the active-session route, to read progress while the iteration moves through analysis and replay. When `latestIteration.status` is `ready`, compare the original and replayed answer snapshots, then inspect `changes` for the proposed draft IDs and root-cause details. ## Shared objects The session endpoints return a `FixReviewSession` shape. For the full field list, see [Get active fix-review session](/en/api-reference/get-active-fix-review-session#fixreviewsession-object). Key fields to handle in integrations: * `sessionId`: review session ID for the selected response. * `latestIteration`: the newest queued, running, or completed review iteration. * `iterations`: all iterations in the session, ordered newest first. * `originalAnswerSnapshot`: the response Fini originally sent. * `latestIteration.newAnswerSnapshot`: the replayed answer generated after the proposed fix. * `latestIteration.changes`: draft prompt, article, or rule recommendations created by the review. # Refresh sources Source: https://docs.usefini.com/en/api-reference/refresh-sources POST https://api-prod.usefini.com/v2/documents/public/refresh Re-fetch existing source IDs so Fini can detect upstream changes and update linked knowledge. Use this route when the upstream content behind existing sources has changed and you want Fini to re-fetch those sources. Refreshing sources is the first step in the knowledge-refresh workflow. After the refresh completes, use [List sources](/en/api-reference/list-sources) with `changed=true`, then call [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge) on those changed source IDs. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Body parameters Existing source IDs to requeue for refresh. ## Response The response is a top-level array of source IDs accepted for refresh. Source IDs that were queued for refresh. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/documents/public/refresh' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "documentIds": [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "35b4838a-4136-4f6c-a530-8f17cb47566d" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/documents/public/refresh', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'documentIds': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/documents/public/refresh", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "documentIds": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ] }, ) data = response.json() ``` ```json 200 OK theme={null} [ "5d9f67a8-d853-4af4-b7ce-23ebba1245e5", "35b4838a-4136-4f6c-a530-8f17cb47566d" ] ``` Raw-file sources cannot be refreshed through this route. Delete and re-upload them instead. ## Errors The request body is malformed, `documentIds` is missing or empty, one of the source IDs does not exist, or you tried to refresh a raw-file source. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope, or the source IDs belong to a different workspace. Fini failed while queueing or processing the refresh. Retry once, then inspect the affected IDs in [List sources](/en/api-reference/list-sources). # Register provider resources Source: https://docs.usefini.com/en/api-reference/register-provider-resources POST https://api-prod.usefini.com/v2/documents/public/resources/{provider} Create or update source records from provider resources. Step 2 of the connected-source flow. Creates or updates source records for the resources you discovered with [List provider resources](/en/api-reference/list-provider-resources), and returns the resulting source IDs in the wire-format fields `addedDocumentIds` and `updatedDocumentIds`. This route does **not** queue ingestion by itself. It only creates source records. To actually start processing, call [Ingest sources](/en/api-reference/ingest-sources) next, passing the IDs returned by this route. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Provider name. Supported values: `notion`, `zendesk`, `confluence`. Must match a provider that's already connected in the workspace. ## Body parameters Array of resource objects to register. Each resource accepts the fields below. Provider URL for the resource. Resource title. Provider-specific identifier (e.g., the Notion page ID). Resource MIME type. Typically taken from the discovery response. Optional internal storage URL. Optional provider-specific type (e.g., Notion `object: "page"`). ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/documents/public/resources/notion' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "resources": [ { "originalUrl": "https://www.notion.so/fini/Billing-FAQ-123456", "title": "Billing FAQ", "externalId": "123456", "mimeType": "text/markdown", "object": "page" } ] }' ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/documents/public/resources/notion", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "resources": [ { "originalUrl": "https://www.notion.so/fini/Billing-FAQ-123456", "title": "Billing FAQ", "externalId": "123456", "mimeType": "text/markdown", "object": "page", } ] }, ) data = response.json() ``` ```javascript Node.js theme={null} const response = await fetch( "https://api-prod.usefini.com/v2/documents/public/resources/notion", { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ resources: [ { originalUrl: "https://www.notion.so/fini/Billing-FAQ-123456", title: "Billing FAQ", externalId: "123456", mimeType: "text/markdown", object: "page", }, ], }), } ); const data = await response.json(); ``` ## Response Source IDs for resources that were newly registered. Source IDs for resources that already existed in the workspace and had their metadata updated. ```json 200 OK theme={null} { "provider": "notion", "resources": [ { "id": "page_123", "title": "Refund policy", "type": "page", "path": "Policies / Refund policy" } ] } ``` ## Next step Pass the returned `addedDocumentIds` and `updatedDocumentIds` into [Ingest sources](/en/api-reference/ingest-sources): * Put new IDs into `documentIdsToAdd` to ingest them for the first time. * Put existing IDs into `documentIdsToRefresh` to re-process them. Without that follow-up call, the source records exist but no content gets processed. ## Errors The provider is not supported on the public route, not connected in the workspace, or one of the resource objects is missing required fields (`originalUrl`, `title`, `externalId`, `mimeType`). The API key is missing, malformed, revoked, or invalid. Confirm `Authorization: Bearer fini_...` with the full key. The API key doesn't include the `write` scope, or it's scoped to a different workspace. Expected. This route only creates source records. It doesn't queue ingestion. Call [Ingest sources](/en/api-reference/ingest-sources) with the returned IDs to start processing. # Replays Source: https://docs.usefini.com/en/api-reference/replays Create and inspect replay conversations through the public API. Replays run an existing conversation through the current agent configuration so you can compare a previous answer with what Fini would do now. Use them after a prompt, knowledge, Rulebook, or model change to verify a known conversation before you roll the change into broader testing. Replay runs create separate replay conversations. They do not overwrite the original conversation, publish a fix, or apply prompt, knowledge, or rule changes by themselves. ## Endpoints | Method | Path | Scope | Purpose | | ------ | ------------------------------------------------- | ------- | ----------------------------------------------------------------- | | `POST` | `/v2/replays/public` | `write` | Create and run a replay from a target Fini response. | | `GET` | `/v2/replays/interactions/{interactionId}/public` | `read` | List replay conversations created from one original conversation. | | `GET` | `/v2/replays/{id}/public` | `read` | Fetch one replay conversation. | | `GET` | `/v2/replays/{id}/events/public` | `read` | Fetch the events for one replay conversation. | ## Replay modes Replays the conversation up to the user event linked to the target response. This is the default mode when `mode` is omitted. Replays only the selected response turn. ## Model overrides `mlModels` lets you override model selection for one replay run without changing the agent's saved configuration. Model name used for the planning step. Model name used for knowledge search. Model name used for answer generation. Model name used for tag selection. The API accepts only these four operation keys. If `mlModels` is present, it must contain at least one supported operation and every value must be a non-empty string. ## Related pages Start a replay for a known Fini response event. See every replay created from one original conversation. Fetch the replay conversation record. Fetch the message events created during the replay. # Overview Source: https://docs.usefini.com/en/api-reference/reply-rules Read the conditions that decide whether an agent sends a direct reply, adds an internal comment, or sends no reply. Reply rules are the API form of **Automations > Reply Rules** in the Fini dashboard. They decide how an agent responds when workspace-specific conditions match. The API currently supports read-only access. Use the configured rules endpoint to audit active behavior, and use fields context to resolve condition paths into customer-friendly labels and available values. ## Endpoints Read the no reply, internal comment, and direct reply rule slots. Read the fields, operators, sources, attributes, and tags available to conditions. ## Authentication Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `read` scope. The workspace is derived from the API key. These endpoints do not accept a workspace ID. ## Reply rule collection The collection always contains three slots. A slot without a saved rule returns `conditions: []` and `isEnabled: false`. Conditions under which the agent sends no customer-facing reply. Conditions under which the agent adds a note visible only to the support team. Conditions under which the agent sends a reply directly to the customer. ## ReplyRule object `NO_REPLY`, `INTERNAL_COMMENT`, or `DIRECT_REPLY`. Condition groups evaluated for this behavior. An empty array means no rule is configured. Whether Fini evaluates this rule. Saved rule ID. Omitted for a default empty slot. Workspace ID recorded on a saved rule. Omitted for a default empty slot. ISO 8601 creation timestamp. Omitted for a default empty slot. ISO 8601 last-update timestamp. Omitted for a default empty slot. ## Condition object `SCALAR` for predicates against individual values, or `ARRAY` for quantified array conditions. Comparisons with `left.path`, `left.dataType`, `operator`, and a `right.value` or `right.path`. `ANY`, `ALL`, or `NONE` for an array condition. Array path and item type used by an array condition. ## Errors The API key is missing, malformed, revoked, or invalid. The API key does not include the `read` scope. Fini failed while loading reply rules or their fields context. # Mark feedback resolved Source: https://docs.usefini.com/en/api-reference/resolve-conversation-feedback POST https://api-prod.usefini.com/v2/hc-interactions/{id}/feedback-resolved/public Mark a negatively rated conversation event as resolved or unresolved. Updates the resolution flag on one event, then recalculates the parent conversation's `resolved` value from all negatively rated Fini responses in that conversation. Use [Send conversation feedback](/en/api-reference/send-feedback-conversation) first to record a thumbs-down event, then call this endpoint when the issue behind that feedback has been handled. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. Send `application/json`. ## Path parameters Conversation ID containing the event. ## Body parameters ID of the event to update. The event must belong to the conversation and workspace. Whether the feedback on this event has been resolved. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/feedback-resolved/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "resolved": true }' ``` ```python Python theme={null} import requests conversation_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.post( f"https://api-prod.usefini.com/v2/hc-interactions/{conversation_id}/feedback-resolved/public", headers={"Authorization": "Bearer fini_your_api_key"}, json={ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "resolved": True, }, ) result = response.json() ``` ```javascript Node.js theme={null} const conversationId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/${conversationId}/feedback-resolved/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ eventId: "f61a9a11-2c3b-4704-8f57-7078854d87cf", resolved: true, }), } ); const result = await response.json(); ``` ## Response `true` after the event and conversation resolution state have been updated. ```json 200 OK theme={null} { "success": true } ``` ## Resolution recalculation After the event is updated, Fini examines all Fini-authored events with `approved=false`: * no negatively rated Fini events sets the conversation's `resolved` value to `null` * all negatively rated Fini events resolved sets it to `true` * any unresolved negatively rated Fini event sets it to `false` ## Errors The body fails validation. `eventId` must be a non-empty string, and `resolved` must be a boolean. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The conversation or event is inaccessible, the conversation has no events, or the supplied event does not exist in the conversation. Fini could not load or update the requested conversation event. # Revert article version Source: https://docs.usefini.com/en/api-reference/revert-article-version POST https://api-prod.usefini.com/v2/hc-articles/{id}/revert/public Revert an article to a saved history version. Reverts an article to a saved history version. This changes live knowledge content, so use it only when your workflow intentionally rolls back an article. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Article ID. ## Body parameters Article version number to restore. ## Response Returns the reverted article. ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/revert/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "version": 0 }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/revert/public', { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'version': 0 } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.post( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/revert/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "version": 0 }, ) data = response.json() ``` ```json 201 Created theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` This route writes to the knowledge graph immediately. If you need review before changing live answers, create or update a draft instead. # Send conversation feedback Source: https://docs.usefini.com/en/api-reference/send-feedback-conversation POST https://api-prod.usefini.com/v2/hc-interactions/{id}/feedback/public Record thumbs-up or thumbs-down feedback on an event and recalculate the conversation's resolution state. Records feedback on an event as thumbs up, thumbs down, or unrated. After saving the feedback, Fini recalculates the conversation's `resolved` value from its negatively rated Fini responses. The request field still uses `approved` for API compatibility. Treat `approved` as the event feedback value: `true` means thumbs up, `false` means thumbs down, and `null` clears the feedback. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. Send `application/json`. ## Path parameters Conversation ID containing the event. ## Body parameters ID of the event to update. The event must belong to the conversation and workspace. Feedback value. Send `true` for thumbs up, `false` for thumbs down, or `null` to clear the feedback. Include this field when changing the feedback. ## Request example ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/hc-interactions/0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8/feedback/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "approved": false }' ``` ```python Python theme={null} import requests conversation_id = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8" response = requests.post( f"https://api-prod.usefini.com/v2/hc-interactions/{conversation_id}/feedback/public", headers={"Authorization": "Bearer fini_your_api_key"}, json={ "eventId": "f61a9a11-2c3b-4704-8f57-7078854d87cf", "approved": False, }, ) result = response.json() ``` ```javascript Node.js theme={null} const conversationId = "0b8626b0-4cc8-4a3d-8fc2-f18ad1a4a1a8"; const response = await fetch( `https://api-prod.usefini.com/v2/hc-interactions/${conversationId}/feedback/public`, { method: "POST", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ eventId: "f61a9a11-2c3b-4704-8f57-7078854d87cf", approved: false, }), } ); const result = await response.json(); ``` ## Response `true` after the event feedback and conversation state have been updated. ```json 200 OK theme={null} { "success": true } ``` ```json 400 Bad Request theme={null} { "statusCode": 400, "message": ["approved must be a boolean value"], "error": "Bad Request" } ``` ```json 403 Forbidden theme={null} { "statusCode": 403, "message": "API key does not have the required scope for this operation", "error": "Forbidden" } ``` ## Resolution recalculation After the feedback is saved, Fini examines all Fini-authored events with `approved=false`: * no negatively rated Fini events sets the conversation's `resolved` value to `null` * all negatively rated Fini events resolved sets it to `true` * any unresolved negatively rated Fini event sets it to `false` ## Errors The body fails validation. `eventId` must be a non-empty string, and `approved`, when provided, must be `true`, `false`, or `null`. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The conversation or event is inaccessible, the conversation has no events, or the supplied event does not exist in the conversation. Fini could not load or update the requested conversation event. # Overview Source: https://docs.usefini.com/en/api-reference/sources Add raw content to Fini, ingest it into source records, and move it into the knowledge workflow. Sources are the raw inputs that feed Fini's knowledge system. Use these routes to bring content into Fini from the web or connected providers, monitor ingestion, and refresh or remove source records later. The wire format still uses `document`, `documentId`, and `/v2/documents/...` because that is the current API contract. In this reference, we call them **sources** because they are inputs to knowledge, not the knowledge your agents retrieve from directly. A source becomes useful in Fini when you ingest it, optionally set up your [Knowledge](/en/api-reference/knowledge) structure for first-time imports, generate knowledge from the ingested content, review the result, and then organize and assign that knowledge to the right agent. ## Reference pages `GET /v2/documents/public` — paginate through every source record in the workspace. `GET /v2/documents/public/:id` — fetch one source record by ID. `GET /v2/documents/public/resources/:provider` — discover what is importable from a connected provider. `POST /v2/documents/public/resources/:provider` — create source records for the resources you picked. `POST /v2/documents/public` — queue ingestion or refresh jobs. `POST /v2/documents/public/deep-crawl/links` — discover more web URLs from one or more seed links. `POST /v2/documents/public/refresh` — refresh existing source IDs. `DELETE /v2/documents/public` — delete source records, optionally deleting linked Articles too. Generate knowledge from sources, scaffold the first tree, and move from drafts into live knowledge. Read, create, update, draft, publish, and delete live articles directly. Manage folders, move articles between folders, and assign them to agents. The three `GET` routes require `read`. Resource registration, ingestion, crawl, refresh, and delete routes require `write`. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | ------------------------------------------ | ------- | -------------------------------------------------------------------------- | | `GET` | `/v2/documents/public` | `read` | List source records in the workspace. | | `GET` | `/v2/documents/public/:id` | `read` | Fetch one source record by ID. | | `GET` | `/v2/documents/public/resources/:provider` | `read` | Discover importable content from a connected provider. | | `POST` | `/v2/documents/public/resources/:provider` | `write` | Register provider resources as source records. | | `POST` | `/v2/documents/public` | `write` | Ingest new sources or refresh existing ones through the add-sources route. | | `POST` | `/v2/documents/public/deep-crawl/links` | `write` | Discover more web URLs from one or more seed links before ingesting them. | | `POST` | `/v2/documents/public/refresh` | `write` | Refresh existing source IDs. | | `DELETE` | `/v2/documents/public` | `write` | Delete source records, optionally deleting linked Articles too. | ## Add sources There are two ways to add sources into Fini through the public API: * Web links: pass URLs directly to [Ingest sources](/en/api-reference/ingest-sources). * Connected providers: discover provider resources, register them, then ingest the returned source IDs. Currently supported connected providers in the public API are `zendesk`, `confluence`, and `notion`. | Source type | How to add it | What the discovery response looks like | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | `web` | Call [Ingest sources](/en/api-reference/ingest-sources) directly with URLs in `documentIdsToAdd` | No discovery call. You can optionally crawl first. | | `zendesk` | Call [List provider resources](/en/api-reference/list-provider-resources), then [Register provider resources](/en/api-reference/register-provider-resources), then [Ingest sources](/en/api-reference/ingest-sources) | Category tree with nested sections and articles | | `confluence` | Call [List provider resources](/en/api-reference/list-provider-resources), then [Register provider resources](/en/api-reference/register-provider-resources), then [Ingest sources](/en/api-reference/ingest-sources) | Array of spaces with nested pages | | `notion` | Call [List provider resources](/en/api-reference/list-provider-resources), then [Register provider resources](/en/api-reference/register-provider-resources), then [Ingest sources](/en/api-reference/ingest-sources) | Flat array of importable resources | Provider-specific response objects and full examples live on [List provider resources](/en/api-reference/list-provider-resources). That page owns the actual provider response shapes: `NotionResource[]`, `ZendeskCategory[]`, and `ConfluenceSpace[]`. ### Optional: crawl web links before ingesting Crawling is useful when you have one or a few seed URLs and want Fini to discover more web pages before you ingest them. It is a separate API call, not behavior inside `POST /v2/documents/public`. Call [Crawl links](/en/api-reference/deep-crawl-links). The response returns discovered URLs in `data`. Use the returned URLs as the input set for your web-source ingestion flow. Call [Ingest sources](/en/api-reference/ingest-sources) with `source: "web"` and place those URLs into `documentIdsToAdd`. The endpoint map above is the full public route surface for Sources. Use the child pages in this section for the detailed request and response references for each route family. ## Refresh knowledge from changed sources If you already have knowledge in Fini for a set of sources and the upstream content changes, the refresh path is: refresh the sources, filter the ones that actually changed, then bulk generate and save knowledge for just those source IDs. Call [Refresh sources](/en/api-reference/refresh-sources) with the source IDs you already have. For web content, those are the source records created the first time you ingested the URLs. Use [List sources](/en/api-reference/list-sources) or [Get source](/en/api-reference/get-source) and wait for `linkedJobStatus` to move to `COMPLETED`. Call [List sources](/en/api-reference/list-sources) with `changed=true`. If you want only web content, also pass `source=web`. Keep the source records that already have a `linkedKnowledgeId` because those are the ones that already back knowledge in Fini. Call [Bulk generate knowledge](/en/api-reference/bulk-generate-knowledge) with the changed `documentIds`. Set `isDraft: true` if you want review before the update goes live. Set `isDraft: false` only when you want the update saved live immediately. Use [Check knowledge jobs](/en/api-reference/check-knowledge-jobs) until the queued jobs finish. If you kept the updates as drafts, review and publish them before expecting agent answers to change. When the generate-and-save job succeeds for a source-backed update, Fini syncs the linked article and clears that source's `changed` flag. ## Why the Sources API isn't working This is usually expected. Source registration and ingestion only get the raw content into Fini. You still need to create knowledge from that source, and the recommended path is to review the result before it goes live. Ingestion is asynchronous. Poll [List sources](/en/api-reference/list-sources) or [Get source](/en/api-reference/get-source) and watch `linkedJobStatus`, `success`, and `error`. If a source stays `PENDING` for longer than expected, inspect `error` on the source record. When `source` is `web`, the values in `documentIdsToAdd` and `documentIdsToRefresh` must be URLs, not source IDs. The wire format reuses the same field names across sources, which is easy to miss. The provider isn't valid for the public route, or it's not connected in the workspace yet. The public provider routes accept `notion`, `zendesk`, and `confluence`. Connect the provider in the dashboard first. Resources that have already been imported successfully from that provider are excluded from the response. Discovery is for finding new content, not auditing what is already in Fini. Use [List sources](/en/api-reference/list-sources) with the provider as a `source` filter to see what is already imported. Common causes are a malformed body, an empty required array, or trying to refresh a raw-file source. Web crawl expects seed URLs in `links`, and refresh expects existing source IDs in `documentIds`. Retry once, then inspect the affected source IDs in [List sources](/en/api-reference/list-sources). If the problem persists, the workspace may contain one or more invalid or inaccessible records that need support help. # Start a run Source: https://docs.usefini.com/en/api-reference/start-test-set-run POST https://api-prod.usefini.com/v2/test-sets/{testSetId}/runs/public Queue an asynchronous run for one test set. Queues a run and returns the created run with `status: "running"` and `result: null`. Poll [Get a run](/en/api-reference/get-test-set-run) until `status` becomes `completed` or `failed`. Runs evaluate the conversations in the set against live agent behavior. If the conversations invoke Actions, those Actions can call your configured external APIs. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. ## Path parameters Test set ID. ## Response Returns the created [Run object](/en/api-reference/test-sets#run-object). ```bash cURL theme={null} curl --request POST \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/runs/public' \ --header 'Authorization: Bearer fini_your_api_key' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/runs/public`, { method: 'POST', headers: { Authorization: 'Bearer fini_your_api_key' } }); const run = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.post( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/runs/public", headers={"Authorization": "Bearer fini_your_api_key"}, ) run = response.json() ``` ```json 202 Accepted theme={null} { "id": "5afd818a-a5f9-4e1b-9619-3c7191c12d9a", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "status": "running", "result": null, "createdBy": null, "createdAt": "2026-07-28T09:01:14.000Z", "updatedAt": "2026-07-28T09:01:14.000Z" } ``` # Overview Source: https://docs.usefini.com/en/api-reference/tag-groups Section hub for reading and managing tag groups through Fini's public API. Tag groups are the top-level classification buckets behind [Configuration → Tags](/en/configuration/tags). Every tag belongs to exactly one group. Use these public routes to read both Fini-shipped default groups and workspace-owned custom groups, or to create and manage custom groups from your backend. The API field `prompt` is the wire-format name for the dashboard's **AI Instructions** field. Read routes return both workspace-owned custom groups and Fini-shipped default groups. In the response, custom groups have a workspace `companyId`, while default groups return `companyId: null`. Mandatory groups, such as Conversation Status, return `mandatory: true`. ## Reference pages `GET /v2/tag-groups/public` - list the tag groups visible in the workspace. `GET /v2/tag-groups/{id}/public` - fetch one tag group by ID. `POST /v2/tag-groups/public` - create a custom tag group. `PUT /v2/tag-groups/{id}/public` - update a custom tag group. `DELETE /v2/tag-groups/{id}/public` - delete a custom tag group. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | --------------------------- | ------- | -------------------------------------------------------------------------------------- | | `GET` | `/v2/tag-groups/public` | `read` | List the tag groups available in the workspace, including Fini-shipped default groups. | | `GET` | `/v2/tag-groups/:id/public` | `read` | Fetch one tag group by ID. | | `POST` | `/v2/tag-groups/public` | `write` | Create a custom tag group. | | `PUT` | `/v2/tag-groups/:id/public` | `write` | Update a custom tag group. | | `DELETE` | `/v2/tag-groups/:id/public` | `write` | Delete a custom tag group. | ## TagGroup object Tag group ID. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. Workspace ID that owns the tag group. `null` indicates a Fini-shipped default group. Group title shown in the dashboard and used as the human-readable name for the classification dimension. Human-readable description for the group. AI-instruction text that teaches the model how to apply the group's tags. This is the API name for the dashboard's **AI Instructions** field. Whether the group allows multiple tags to be applied to the same conversation. Whether the group is Fini-mandatory and not intended for deletion or disabling. Whether this is an output-only tag group. If `true`, the group is for post-classification/reporting use and will not be available as a Rulebook condition, including in intent-based rules. Use the child pages in this section for the detailed request and response reference for each route. # Overview Source: https://docs.usefini.com/en/api-reference/tags Section hub for reading and managing tags through Fini's public API. Tags are the individual values inside a tag group. There is no top-level public `list all tags` route. Instead, the API lets you fetch one tag by ID, list the tags inside one group, or list tags across a specific set of group IDs. If you need every tag in the workspace, first call [Tag groups](/en/api-reference/tag-groups) to collect the group IDs you care about, then call `GET /v2/tag-groups/tags/public` with those `tagGroupIds`. Path semantics are asymmetric in the current controller: * `POST /v2/tag-groups/{id}/tags/public` uses `{id}` as the **tag group ID** * `PUT /v2/tag-groups/tags/{id}/public` uses `{id}` as the **tag ID** * `DELETE /v2/tag-groups/tags/{id}/public` uses `{id}` as the **tag ID** ## Reference pages `GET /v2/tags/{id}/public` - fetch one tag by ID. `GET /v2/tag-groups/{id}/tags/public` - list the tags in one tag group. `GET /v2/tag-groups/tags/public` - list tags across one or more tag groups. `POST /v2/tag-groups/{id}/tags/public` - create a tag inside one tag group. `PUT /v2/tag-groups/tags/{id}/public` - update one tag by tag ID. `DELETE /v2/tag-groups/tags/{id}/public` - delete one tag by tag ID. ## Endpoint map | Method | Path | Scope | Purpose | | -------- | -------------------------------- | ------- | ------------------------------------------------------------------------ | | `GET` | `/v2/tags/:id/public` | `read` | Fetch one tag by ID. | | `GET` | `/v2/tag-groups/:id/tags/public` | `read` | List the tags inside one tag group. | | `GET` | `/v2/tag-groups/tags/public` | `read` | List tags across one or more tag groups as a flat array. | | `POST` | `/v2/tag-groups/:id/tags/public` | `write` | Create a tag inside a tag group. The path parameter is the tag group ID. | | `PUT` | `/v2/tag-groups/tags/:id/public` | `write` | Update one tag. The path parameter is the tag ID. | | `DELETE` | `/v2/tag-groups/tags/:id/public` | `write` | Delete one tag. The path parameter is the tag ID. | ## Tag object Tag ID. ISO 8601 creation timestamp. ID of the tag group that owns this tag. Tag label. Optional tag description or instruction text. Use the child pages in this section for the detailed request and response reference for each route. # Overview Source: https://docs.usefini.com/en/api-reference/test-sets Create Test Suite regression sets, attach criteria, start runs, and read run results through Fini's public API. Test sets are the API form of the dashboard [Test Suite](/en/testing/test-suite). A test set groups existing conversations, attaches one or more grading criteria, and queues asynchronous runs that evaluate those conversations against the current agent behavior. Use these routes when you want to seed regression checks from conversations already in Fini, manage their criteria from your backend, or trigger a run after changing prompts, knowledge, rules, or actions. Test set runs evaluate existing conversation IDs. Create or import the conversations first, then pass their IDs in `conversationIds` when you create or update a test set. ## Endpoints Return every test set in the workspace, newest first. Create a set from one to 200 existing conversation IDs. Read default criteria and deterministic-condition fields. Fetch a test set with its resolved criteria. Update the set name, description, or conversation list. Delete a set after active runs finish. Attach default or custom criteria to a set. Change one criterion on a set. Remove one criterion from a set. Page through run summaries for one set. Queue an asynchronous evaluation run. Fetch one run and its detailed result. ## Authentication Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` Write routes also require `Content-Type: application/json` when they send a body. ## TestSet object Test set ID. Workspace ID that owns the test set. This field is omitted from list summaries. Test set name. Optional description. Existing Fini conversation IDs included in the set. The API accepts 1 to 200 UUIDs. Conversation summaries returned by detail responses. Each item includes `id` and `subject`, where `subject` can be `null` when no subject preview is available. User ID that created the set. API-created records can be `null`. ISO 8601 creation timestamp. ISO 8601 last-update timestamp. List responses return `conversationCount` and `criteriaCount` instead of the full `conversationIds` and `conversations` arrays. ## Criterion object Criterion ID. Test set that owns the criterion. Default criteria return `null`. Workspace that owns the criterion. Fini-provided defaults can return `null`. Default criterion copied into this test set, if this criterion was created from a default. Criterion label. One of `deterministic`, `basic_judge`, or `complex_judge`. Judge prompt for LLM-graded criteria. What should count as a pass for LLM-graded criteria. What should count as a fail for LLM-graded criteria. Deterministic condition. Allowed root paths are `knowledgeSearchUsed`, `usedArticles`, `usedKnowledgeFolders`, `intentRules`, `tagGroups`, and `replyTypes`. Whether failing this criterion should make the conversation fail overall. Whether the criterion is active. ## Run object Test run ID. Test set evaluated by the run. `running`, `completed`, or `failed`. Full result for [Get a run](/en/api-reference/get-test-set-run). While the run is queued or processing, this is `null`. User ID that started the run. API-started runs can be `null`. ### Result shape When a run completes, `result.summary` contains aggregate counts and `result.conversations` contains per-conversation results. Overall verdict, `pass` or `fail`. Number of conversations evaluated. Conversations with a passing result. Conversations with a failing result. Conversations that errored during evaluation. Criterion-level verdicts, reasoning, and evidence for each evaluated conversation. Subject preview for the evaluated conversation. This can be `null` when the conversation has no subject. ## Errors The request body or query parameters failed validation. Common cases: empty names, invalid UUIDs, more than 200 conversation IDs, no criteria before starting a run, or invalid criterion definitions. The API key is missing, malformed, revoked, or invalid. The API key does not include the required `read` or `write` scope. The test set, criterion, run, default criterion, or conversation does not exist in your workspace. The test set has an active run and cannot be deleted until the run finishes. # Update article Source: https://docs.usefini.com/en/api-reference/update-article PUT https://api-prod.usefini.com/v2/hc-articles/{id}/public Update an existing article. Use this route to change the content or metadata of an existing article. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Article ID to update. ## Body parameters Updated article title. Updated main knowledge body. Updated instructions the agent should apply when using this article. Updated question prompts for the article. Updated keywords for the article. Updated escalation flag. Updated active state. Updated help-center visibility. This update route does not accept `parentFolderId`, `isDraft`, or `origin`. Use [Move article](/en/api-reference/move-article) to change folders. ## Response Returns the full updated article object. See [Manage knowledge](/en/api-reference/manage-knowledge) for the shared article fields. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "questions": [ "How do refunds work?" ], "keywords": [ "refund" ], "escalation": true, "active": false, "public": true }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PUT', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'title': 'Refund policy', 'mainKnowledge': 'Customers can request a refund within 30 days of purchase.', 'agentInstruction': '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312', 'questions': [ 'How do refunds work?' ], 'keywords': [ 'refund' ], 'escalation': true, 'active': false, 'public': true } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.put( "https://api-prod.usefini.com/v2/hc-articles/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312", "questions": [ "How do refunds work?" ], "keywords": [ "refund" ], "escalation": True, "active": False, "public": True }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3", "title": "Refund policy", "mainKnowledge": "Customers can request a refund within 30 days of purchase.", "agentInstruction": "Use this article for refund eligibility questions.", "questions": [ "Can I get a refund?" ], "keywords": [ "refund", "billing" ], "escalation": false, "parentFolderId": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "isDraft": false, "origin": "api", "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` The response includes the article's latest `version` after the update is applied. ## Errors The request body is malformed or one of the required arrays is empty. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The article does not exist in the workspace. # Update Business Rule Source: https://docs.usefini.com/en/api-reference/update-business-rule PATCH https://api-prod.usefini.com/v2/hc-rules/{id}/public Update a custom or template-based Business Rule. Updates a Business Rule directly. Business Rules do not create versions. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Business Rule ID. ## Body parameters Updated rule name. Updated workflow description. Updated source. The current enum value is `widget`. Updated trigger. The current enum value is `on_escalation`. Updated custom rule tree. Template-based rules cannot define this field. Updated runtime input bindings. Updated agent assignments. ## Response Returns the updated [`Rule`](/en/api-reference/rules#rule-object). ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "source": "widget", "triggerType": "on_escalation", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'name': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'source': 'widget', 'triggerType': 'on_escalation', 'flowConfig': { 'type': 'reply', 'message': 'Escalate refund requests with order context.' }, 'inputSchema': [ '4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3' ], 'botIds': [ '2a1cf0f0-f35d-46ad-8e61-a15c86b2b312' ] } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.patch( "https://api-prod.usefini.com/v2/hc-rules/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "name": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "source": "widget", "triggerType": "on_escalation", "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "inputSchema": [ "4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3" ], "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ] }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "b8b8d87b-2f0c-47f6-8a8a-546da73e0820", "name": "Refund escalation", "description": "Route refund requests to the right workflow.", "type": "business", "status": null, "source": "widget", "triggerType": "on_escalation", "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "flowConfig": { "type": "reply", "message": "Escalate refund requests with order context." }, "version": null, "versionId": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The body is malformed, a template-based rule defines `flowConfig`, or a referenced agent, action, or widget form is invalid. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. The Business Rule does not exist in your workspace. # Update knowledge folder Source: https://docs.usefini.com/en/api-reference/update-knowledge-folder PUT https://api-prod.usefini.com/v2/hc-folders/{id}/public Update a folder's title, description, or active state. Use this route to update an existing folder in the knowledge tree. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Folder ID to update. ## Body parameters Updated folder title. Updated folder description. Whether the folder should remain active. ## Response Returns the full updated knowledge folder object. See [Organize knowledge](/en/api-reference/organize-knowledge) for the shared folder fields. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "title": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "active": false }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public', { method: 'PUT', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'title': 'Refund policy', 'description': 'Refund-policy conversations to re-check before prompt changes.', 'active': false } ) }); const data = await response.json(); ``` ```python Python theme={null} import requests response = requests.put( "https://api-prod.usefini.com/v2/hc-folders/4f5ef695-d03b-4d56-8fef-7f2bd5c17ef3/public", headers={"Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json"}, json={ "title": "Refund policy", "description": "Refund-policy conversations to re-check before prompt changes.", "active": False }, ) data = response.json() ``` ```json 200 OK theme={null} { "id": "0f4da4fe-b2ae-4787-8c3b-854f36d9eb1b", "title": "Billing", "description": "Refunds, invoices, and subscription changes.", "parentFolderId": null, "active": true, "botIds": [ "2a1cf0f0-f35d-46ad-8e61-a15c86b2b312" ], "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` ## Errors The request body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope. The folder does not exist in the workspace. # Update tag Source: https://docs.usefini.com/en/api-reference/update-tag PUT https://api-prod.usefini.com/v2/tag-groups/tags/{id}/public Update one tag by tag ID. Updates one [`Tag`](/en/api-reference/tags#tag-object). The `{id}` path segment is the tag ID on this route, not the tag group ID. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Tag ID to update. ## Body parameters Updated tag label. Updated tag description or instruction text. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/tag-groups/tags/0dc53764-a417-4a4f-b7f4-63149529f530/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "tagName": "resolved_without_escalation", "tagDescription": "Use when the assistant fully resolved the request without handing off." }' ``` ```python Python theme={null} import requests tag_id = "0dc53764-a417-4a4f-b7f4-63149529f530" response = requests.put( f"https://api-prod.usefini.com/v2/tag-groups/tags/{tag_id}/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "tagName": "resolved_without_escalation", "tagDescription": "Use when the assistant fully resolved the request without handing off.", }, ) tag = response.json() ``` ```javascript Node.js theme={null} const tagId = "0dc53764-a417-4a4f-b7f4-63149529f530"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/tags/${tagId}/public`, { method: "PUT", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ tagName: "resolved_without_escalation", tagDescription: "Use when the assistant fully resolved the request without handing off.", }), } ); const tag = await response.json(); ``` ## Response Returns the updated [`Tag`](/en/api-reference/tags#tag-object). ```json 200 OK theme={null} { "id": "0dc53764-a417-4a4f-b7f4-63149529f530", "createdAt": "2026-06-19T07:32:10.000Z", "tagGroupId": "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5", "tagName": "resolved_without_escalation", "tagDescription": "Use when the assistant fully resolved the request without handing off." } ``` Current controller behavior: unknown tag IDs currently surface as `500 Internal Server Error` on this route. Tags in Fini-managed groups are also not part of the supported write contract. ## Errors The body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while resolving the tag or updating it in storage. # Update tag group Source: https://docs.usefini.com/en/api-reference/update-tag-group PUT https://api-prod.usefini.com/v2/tag-groups/{id}/public Update a custom tag group. Updates a custom tag group and returns the stored [`TagGroup`](/en/api-reference/tag-groups#taggroup-object). Supported contract: use this route for workspace-owned custom groups. Fini-managed groups are read-only in the product model. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Tag group ID to update. ## Body parameters Updated group title. Updated group description. Updated AI-instruction text. Updated multi-select behavior. Updated flag for output-only groups. If `true`, this group will not be available in Rulebooks, including intent-based rules, so leave it `false` for routing or other Rulebook conditions. ```bash cURL theme={null} curl --request PUT \ --url 'https://api-prod.usefini.com/v2/tag-groups/f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "description": "Post-reply outcome tags for downstream ticket workflows and reporting.", "prompt": "Choose the single outcome tag that best captures the final assistant handling.", "multiselect": false, "isOutputTagGroup": true }' ``` ```python Python theme={null} import requests tag_group_id = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5" response = requests.put( f"https://api-prod.usefini.com/v2/tag-groups/{tag_group_id}/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "description": "Post-reply outcome tags for downstream ticket workflows and reporting.", "prompt": "Choose the single outcome tag that best captures the assistant's final handling.", "multiselect": False, "isOutputTagGroup": True, }, ) tag_group = response.json() ``` ```javascript Node.js theme={null} const tagGroupId = "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5"; const response = await fetch( `https://api-prod.usefini.com/v2/tag-groups/${tagGroupId}/public`, { method: "PUT", headers: { Authorization: "Bearer fini_your_api_key", "Content-Type": "application/json", }, body: JSON.stringify({ description: "Post-reply outcome tags for downstream ticket workflows and reporting.", prompt: "Choose the single outcome tag that best captures the assistant's final handling.", multiselect: false, isOutputTagGroup: true, }), } ); const tagGroup = await response.json(); ``` ## Response Returns the updated [`TagGroup`](/en/api-reference/tag-groups#taggroup-object). ```json 200 OK theme={null} { "id": "f770d0bb-d5ea-44e7-a92a-fcfa2d5a32d5", "createdAt": "2026-06-19T07:30:11.000Z", "companyId": "38ba4db0-31db-4669-bb95-7b8313c4016b", "title": "Resolution Outcome", "description": "Post-reply outcome tags for downstream ticket workflows and reporting.", "prompt": "Choose the single outcome tag that best captures the assistant's final handling.", "multiselect": false, "updatedAt": "2026-06-19T07:46:09.000Z", "mandatory": false, "isOutputTagGroup": true } ``` Current controller behavior: unknown IDs and attempts to update Fini-managed groups currently surface as `500 Internal Server Error` rather than a dedicated `404` or `409`. ## Errors The body is malformed. The API key is missing, malformed, revoked, or invalid. The API key does not include the `write` scope required for this route. Fini failed while updating the tag group. Unknown or non-editable IDs currently surface here as well. # Update a test set Source: https://docs.usefini.com/en/api-reference/update-test-set PATCH https://api-prod.usefini.com/v2/test-sets/{testSetId}/public Update a test set's name, description, or conversation list. Updates one or more test set fields. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Test set ID. ## Body parameters New non-empty name. New description. Send `null` to clear it. Replacement list of one to 200 existing conversation IDs. Each value must be a UUID. ## Response Returns the updated [TestSet object](/en/api-reference/test-sets#testset-object), including resolved criteria and conversation summaries. ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "name": "Refund regression set", "description": "Refund-policy and exchange conversations for release checks.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d" ] }' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/public`, { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Refund regression set', description: 'Refund-policy and exchange conversations for release checks.', conversationIds: [ 'a5221094-72d4-4b9c-8d30-2f785b108bd9', '2dd2b920-f57c-4e92-8a6a-f310d4c8594d' ] }) }); const testSet = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" response = requests.patch( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "name": "Refund regression set", "description": "Refund-policy and exchange conversations for release checks.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d", ], }, ) test_set = response.json() ``` ```json 200 OK theme={null} { "id": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "name": "Refund regression set", "description": "Refund-policy and exchange conversations for release checks.", "conversationIds": [ "a5221094-72d4-4b9c-8d30-2f785b108bd9", "2dd2b920-f57c-4e92-8a6a-f310d4c8594d" ], "conversations": [ { "id": "a5221094-72d4-4b9c-8d30-2f785b108bd9", "subject": "Customer asks about refund eligibility" }, { "id": "2dd2b920-f57c-4e92-8a6a-f310d4c8594d", "subject": "Exchange request after delivery" } ], "criteria": [ { "id": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "defaultCriterionId": null, "name": "Goal resolution", "type": "complex_judge", "judgePrompt": "Judge whether the conversation resolved the user's goal.", "passPrompt": "The user's goal was resolved.", "failPrompt": "The user's goal was not resolved.", "condition": null, "blocking": true, "isActive": true, "createdAt": "2026-07-28T08:56:12.000Z", "updatedAt": "2026-07-28T08:56:12.000Z" } ], "createdBy": null, "createdAt": "2026-07-28T08:55:32.000Z", "updatedAt": "2026-07-28T09:10:18.000Z" } ``` # Update a criterion Source: https://docs.usefini.com/en/api-reference/update-test-set-criterion PATCH https://api-prod.usefini.com/v2/test-sets/{testSetId}/criteria/{criteriaId}/public Update one criterion on a test set. Updates one criterion. For criteria created from a default, only `blocking` can be changed. ## Headers Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope. `application/json` ## Path parameters Test set ID. Criterion ID. ## Body parameters New criterion name for custom criteria. New judge prompt for judge criteria. New pass prompt for judge criteria. New fail prompt for judge criteria. New condition for deterministic criteria. Whether failing this criterion should fail the conversation overall. Whether the criterion is active. ## Response Returns the updated [Criterion object](/en/api-reference/test-sets#criterion-object). ```bash cURL theme={null} curl --request PATCH \ --url 'https://api-prod.usefini.com/v2/test-sets/44c1f705-8e1a-4f61-8c4c-d519d37fb6b7/criteria/96eab02d-3bc3-4b90-ae5b-1a41a1444afa/public' \ --header 'Authorization: Bearer fini_your_api_key' \ --header 'Content-Type: application/json' \ --data '{ "blocking": false, "isActive": true }' ``` ```javascript Node.js theme={null} const testSetId = '44c1f705-8e1a-4f61-8c4c-d519d37fb6b7'; const criteriaId = '96eab02d-3bc3-4b90-ae5b-1a41a1444afa'; const response = await fetch(`https://api-prod.usefini.com/v2/test-sets/${testSetId}/criteria/${criteriaId}/public`, { method: 'PATCH', headers: { Authorization: 'Bearer fini_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ blocking: false, isActive: true }) }); const criterion = await response.json(); ``` ```python Python theme={null} import requests test_set_id = "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7" criteria_id = "96eab02d-3bc3-4b90-ae5b-1a41a1444afa" response = requests.patch( f"https://api-prod.usefini.com/v2/test-sets/{test_set_id}/criteria/{criteria_id}/public", headers={ "Authorization": "Bearer fini_your_api_key", "Content-Type": "application/json", }, json={ "blocking": False, "isActive": True, }, ) criterion = response.json() ``` ```json 200 OK theme={null} { "id": "96eab02d-3bc3-4b90-ae5b-1a41a1444afa", "testSetId": "44c1f705-8e1a-4f61-8c4c-d519d37fb6b7", "companyId": "1d2a4c9f-59f8-4f9c-bd36-6f12e0d5d927", "defaultCriterionId": null, "name": "Goal resolution", "type": "complex_judge", "judgePrompt": "Judge whether the conversation resolved the user's goal.", "passPrompt": "The user's goal was resolved.", "failPrompt": "The user's goal was not resolved.", "condition": null, "blocking": false, "isActive": true, "createdAt": "2026-07-28T08:56:12.000Z", "updatedAt": "2026-07-28T09:12:45.000Z" } ```