# Tender Analysis

## 1. Introduction

The intended use case is to fetch TED notices, split them into LOTs, run an AI evaluation (portfolio fit, quantity, technical complexity), save scored insights to a knowledge base and spreadsheet, and notify stakeholders. The evaluation logic and prompts are configured in the Blockbrain UI; the API is used to automate processing at scale.

All functionality available in the UI is also exposed through the API. The UI should be used to set up the evaluation bot and prompt, while the API should be used to implement automated or large-scale workflows. The complete Blockbrain API documentation is provided here: <https://blocky.theblockbrain.ai/docs>

Before proceeding with the workflow, ensure you have:

1. **Configured your Tender Evaluation bot.**
2. **Defined and saved the evaluation prompt in the Prompt Library and noted the agentTaskId.**
3. **Selected the appropriate LLM model in the bot settings.**
4. **Configured Google Sheets & Drive credentials (if using spreadsheet output).**
5. **Retrieved your `bot_id`, `agentTaskId` as described in Section 4 of this guide.**

## 2. API Basic Workflow

The process for automated tender analysis consists of multiple main steps. It is strongly recommended to create a separate Data Room (conversation) or Insights Folder per publication/notice to maintain isolation between evaluations and enable parallel processing.

### **Step 1 – Create Report Spreadsheet**

Create a new Google Spreadsheet to store tender evaluation results.

* **Endpoint**: POST <https://sheets.googleapis.com/v4/spreadsheets>
* **API Reference**: [Google Sheets API - Spreadsheets.create](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/create)

Example request URL

**`https://sheets.googleapis.com/v4/spreadsheets`**

Example request body

```json
{
  "properties": {
    "title": "TED_Ausschreibungen_2025-07-22_2025-07-29"
  },
  "sheets": [
    {
      "properties": {
        "title": "Summary"
      }
    }
  ]
}
```

Example response body (trimmed)

```json
{
  "spreadsheetId": "1A2b3C4d5E6fG7h8I9j0K",
  "properties": {
    "title": "TED_Ausschreibungen_2025-07-22_2025-07-29"
  },
  "sheets": [
    {
      "properties": {
        "sheetId": 0,
        "title": "Summary"
      }
    }
  ],
  "spreadsheetUrl": "https://docs.google.com/spreadsheets/d/1A2b3C4d5E6fG7h8I9j0K/edit"
}
```

### **Step 2 – Create Insights Folder**

This operation creates a new insights folder in the knowledge base to store generated insights for todays tender batch.

* **Endpoint**: POST /cortex/notes/insight-folder
* **API Reference**: [Create Insights Folder – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-notes/operation/add_insight_folder_cortex_notes_insight_folder_post)

Example request URL

**`https://blocky.theblockbrain.ai/cortex/notes/insight-folder`**

Example request body

```javascript
{
  "name": "2025-07-22-2025-07-29",
  "parentPath": "root/68c7b1cf94bd26b154694306",
  "description": "TED Ausschreibungen der Woche 2025-07-22 bis 2025-07-29"
}
```

Example response body

```javascript
{
  "folderId": "68de93f1fc203c550a278b09",
  "path": "root/68c7b1cf94bd26b154694306/2025-07-22-2025-07-29"
}
```

The response will contain a `folderId` and `path` that identify this insights folder. These are needed for saving insights in subsequent steps.

### **Step 3 – Query TED Notices**

Fetch tender notices from the TED API filtered by CPV codes and dates.

* **Endpoint**: POST <https://tedweb.api.ted.europa.eu/v3/notices/search>
* **API Reference**: [TED Notices Search – API Documentation](https://tedweb.api.ted.europa.eu/redoc)

Example request body

```javascript
{
  "query":"deadline-receipt-request>=20250729 AND publication-date>=today() AND classification-cpv IN (51120000, ...)",
  "page":1,
  "limit":200,
  "fields":[
    "description-lot",
    "title-lot",
    "notice-title",
    "main-classification-lot",
    "quantity-lot",
    "estimated-value-lot",
    "organisation-name-buyer",
    "deadline-receipt-tender-date-lot",
    "links",
    "publication-number"
  ],
  "scope":"ACTIVE"
}
```

### **Step 4 – Split Notices into LOTs**

Split each fetched notice into individual LOT items for per-LOT evaluation.

* Handle array and language-object fields reliably (title-lot, description-lot, main-classification-lot).
* Output: one item per LOT containing original notice metadata.

### **Step 5 – Create Data Room & Submit LOT Content**

Create a conversation (Data Room) per notice or publication-number and submit LOT content to the evaluation bot.

* **Create Data Room Endpoint**: POST /cortex/active-bot/{bot\_id}/convo
* **API Reference**: [Create Data Room – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-active-bot/operation/add_convo_to_bot_cortex_active_bot__bot_id__convo_post)

Example request URL

**`https://blocky.theblockbrain.ai/cortex/active-bot/687e4c1b04e932e500e46c52/convo`**

Example request body

```javascript
{
  "convoName": "PUB-12345",
  "sessionId": "68a70120d6167415e62a8074"
}
```

Example response body

```javascript
{
  "convoId": "68de93f1fc203c550a278b09",
  "activeBotId": "68b968d3e8d7b4710f2b5632"
}
```

* **Submit LOT Content Endpoint**: POST /cortex/completions/v2/user-input
* **API Reference**: [Add User Messages – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-completions/operation/add_user_messages_cortex_completions_user_input_post)

Example request URL

**`https://blocky.theblockbrain.ai/cortex/completions/v2/user-input`**

Example request body

```javascript
{
  "content": "/* JSON with LOT fields: title, description, main-classification-lot, estimated-value-lot, quantity-lot, organisation-name-buyer, deadline-receipt-tender-date-lot, links, publication-number */",
  "actionType": "direct-agent",
  "messageType": "user-question",
  "sessionId": "68a70120d6167415e62a8074",
  "convoId": "68de93f1fc203c550a278b09",
  "agentTaskId": "68926547ce87314fbc4e500b",
  "enableStreaming": false
}
```

If **`enableStreaming`** is enabled, responses are returned token by token using [Streaming](https://api.docs.theblockbrain.ai/concepts/streaming). Concatenate returned new\_token objects to form the final output.

### **Step 6 – Retrieve Evaluation Result**

This operation retrieves the evaluation message detail through the messageId obtained as response in the previous step.

* **Endpoint**: GET /cortex/message/{message\_id}
* **API Reference**: [Get Message Detail – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex/operation/get_message_detail_cortex_message__message_id__get)

Example request URL

**`https://blocky.theblockbrain.ai/cortex/message/{message_id}`**

The evaluation result is the **`content`** of the response body, while the original submitted LOT content is **`targetText`**.

**Alternatively, retrieve the complete message list**

This operation retrieves the complete list of messages for a given conversation (`convoId`).

* **Endpoint**: POST /cortex/message/list
* **API Reference**: [Get Message List – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex/operation/get_message_list_cortex_message_list_post)

Example request URL

**`https://blocky.theblockbrain.ai/cortex/message/list`**

Example request body

```javascript
{
  "convoId": "68de93f1fc203c550a278b09",
  "sessionId": "68a70120d6167415e62a8074"
}
```

### **Step 7 – Scoring & Evaluation Logic**

Compute scores for each LOT using the evaluation bot plus deterministic rules.

* Implementation notes: extract CPV prefixes (first 5 digits), detect quantities via fields or regex in title/description, compute complexity from multiple flag fields.

### **Step 8 – Filter Relevant Results**

Keep only LOTs meeting the relevance threshold (configurable).

* Filter nodes (Only Relevant > 5 Score) and business-rule nodes to remove auto-PASS items.

### **Step 9 – Create Insight from Tender HTML & Save to Knowledge Base**

Download tender HTML, convert to Markdown, create an insight note, generate a shareable link and save the insight to the knowledge base.

* **Download tender HTML**: use `notice.links.htmlDirect.DEU` (fallback to ENG).

* **Convert HTML → Markdown**

* **Create insight note**
  * **Endpoint**: POST /cortex/notes/add-note
  * **API Reference**: [Add Note – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-notes/operation/add_note_cortex_notes_add_note_post)
  * **Example request URL**\
    \&#xNAN;**`https://blocky.theblockbrain.ai/cortex/notes/add-note`**
  * **Example request body**

    ```javascript
    {
      "summary": "<markdown content>",
      "title": "<notice-title.deu>",
      "parent_path": "<folderPath>"
    }
    ```
  * **Example response body (trimmed)**

    ```javascript
    {
      "noteId": "64f3a1b2c9e84d0012345678",
      "body": { /* note metadata */ }
    }
    ```

* **Generate shareable link**
  * **Endpoint**: POST /cortex/notes/share/generate-link
  * **API Reference**: [Generate Share Link – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-notes/operation/generate_share_link_cortex_notes_share_generate_link_post)
  * **Example request URL**\
    \&#xNAN;**`https://blocky.theblockbrain.ai/cortex/notes/share/generate-link`**
  * **Example request body**

    ```javascript
    {
      "noteId": "64f3a1b2c9e84d0012345678",
      "username": "admin@domain",
      "includeReference": true,
      "includeCitation": true
    }
    ```
  * **Example response body (trimmed)**

    ```javascript
    {
      "shareUrl": "https://company.kb.theblockbrain.ai/note/share?shareNote=abcdef123456"
    }
    ```

* **Save insight to knowledge base collection**
  * **Endpoint**: POST /cortex/notes/save-insights-to-knowledge-base
  * **API Reference**: [Save Insights – API Documentation](https://blocky.theblockbrain.ai/redoc#tag/cortex-notes/operation/save_insights_to_kb_cortex_notes_save_insights_to_knowledge_base_post)
  * **Example request URL**\
    \&#xNAN;**`https://blocky.theblockbrain.ai/cortex/notes/save-insights-to-knowledge-base`**
  * **Example request body**

    ```javascript
    {
      "knowledge_folders_destination": [
        {
          "noteIds": [],
          "folderNoteIds": ["<folderId>"]
        }
      ],
      "knowledgeBase": "<knowledgeBaseId>",
      "folderPath": "root"
    }
    ```
  * **Example response body (trimmed)**

    ```javascript
    {
      "status": "success",
      "savedNotes": ["64f3a1b2c9e84d0012345678"]
    }
    ```

### **Step 10 – Append Evaluation to Spreadsheet**

Map evaluation fields to Google Sheets columns and append one row per LOT.

* Typical columns:&#x20;
  * ABC-Rating
  * Score
  * Title-DE
  * HTML-Link-DE
  * Tender-Nr
  * Lot
  * Recommendation
  * CPV-Code
  * HTML-Link-EN
  * Blockbrain Chat Link&#x20;

### **Step 11 – Clean Up Data Rooms (Optional)**

Delete or archive conversations and temporary data rooms after processing to free resources.

* **Endpoint**: DELETE /cortex/conversation/{convoId}

Example request URL

**`https://blocky.theblockbrain.ai/cortex/conversation/68de93f1fc203c550a278b09`**

## Best Practices

1. Create one Insights Folder or Data Room per publication-number to isolate context.
2. Store evaluation prompts in the Prompt Library and reference via `agentTaskId`.
3. Generate a sessionId (UUID) per processing run for traceability.
4. Keep scoring thresholds and weights configurable.
5. Persist raw notice payload and evaluation metadata for audit and re‑scoring.
