# API

***

## 1. Prediction API

* POST `/api/v1/prediction/{your-chatflowid}`

Request Body

<table><thead><tr><th width="192">Key</th><th width="347">Description</th><th>Type</th><th>Required</th></tr></thead><tbody><tr><td>question</td><td>User's question</td><td>string</td><td>Yes</td></tr><tr><td>overrideConfig</td><td>Override existing flow configuration</td><td>object</td><td>No</td></tr><tr><td>history</td><td>Prepend history messages at the start of conversation</td><td>array</td><td>No</td></tr></tbody></table>

You can use the chatflow as API and connect to frontend applications.

<figure><img src="https://662370747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3VoWwSsyrEg0DEvIIjv9%2Fuploads%2Fgit-blob-d3bdadc0f88084a6993c5e929ca83159411678b3%2Fimage%20(16)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

### Override Config

You also have the flexibility to override input configuration with **overrideConfig** property.

<figure><img src="https://662370747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3VoWwSsyrEg0DEvIIjv9%2Fuploads%2Fgit-blob-271be4f53fe45fd4e35ef4b071c9f8a47994e576%2Fimage%20(45).png?alt=media" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="Python" %}

```python
import requests
API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/&#x3C;chatlfowid>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()
    
output = query({
    "question": "Hey, how are you?",
    "overrideConfig": {
        "sessionId": "123",
        "returnSourceDocuments": true
    }
})
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "question": "Hey, how are you?",
    "overrideConfig": {
        "sessionId": "123",
        "returnSourceDocuments": true
    }
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### History

You can prepend history messages to give some context to LLM. For example, if you want the LLM to remember user's name:

{% tabs %}
{% tab title="Python" %}

```python
import requests
API_URL = "http://localhost:3000/api/v1/prediction/&#x3C;chatlfowid>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()
    
output = query({
    "question": "Hey, how are you?",
    "history": [
        {
            "role": "apiMessage",
            "content": "Hello how can I help?"
        },
        {
            "role": "userMessage",
            "content": "Hi my name is Brian"
        },
        {
            "role": "apiMessage",
            "content": "Hi Brian, how can I help?"
        },
    ]
})
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/prediction/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "question": "Hey, how are you?",
    "history": [
        {
            "role": "apiMessage",
            "content": "Hello how can I help?"
        },
        {
            "role": "userMessage",
            "content": "Hi my name is Brian"
        },
        {
            "role": "apiMessage",
            "content": "Hi Brian, how can I help?"
        },
    ]
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Persists Memory

If the chatflow contains [Memory](https://tailwindsdocs.innovativesol.com/chatflows/langchain/memory#memory-nodes) nodes, you can pass a `sessionId` to persists the state of the conversation, so the every subsequent API calls will have context about previous conversation. Otherwise, a new session will be generated each time.

{% tabs %}
{% tab title="Python" %}

```python
import requests
API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/&#x3C;chatlfowid>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()
    
output = query({
    "question": "Hey, how are you?",
    "overrideConfig": {
        "sessionId": "123"
    } 
})
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "question": "Hey, how are you?",
    "overrideConfig": {
        "sessionId": "123"
    }
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Image Uploads

When **Allow Image Upload** is enabled, images can be uploaded from chat interface.

{% tabs %}
{% tab title="Python" %}

```python
import requests
API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/&#x3C;chatlfowid>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()
    
output = query({
    "question": "Can you describe the image?",
    "uploads": [
        {
            "data": 'data:image/png;base64,iVBORw0KGgdM2uN0', # base64 string or url
            "type": 'file', # file | url
            "name": 'image.png',
            "mime": 'image/png'
        }
    ]
})
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "question": "Can you describe the image?",
    "uploads": [
        {
            "data": 'data:image/png;base64,iVBORw0KGgdM2uN0', //base64 string or url
            "type": 'file', //file | url
            "name": 'Flowise.png',
            "mime": 'image/png'
        }
    ]
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Speech to Text

When **Speech to Text** is enabled, users can speak directly into microphone and speech will be transcribed into text.

<div align="left"><figure><img src="https://662370747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3VoWwSsyrEg0DEvIIjv9%2Fuploads%2Fgit-blob-0dd60a403ed7dcb5d2c52af7f222ad3bdb228c5f%2Fimage%20(2)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt="" width="563"><figcaption></figcaption></figure> <figure><img src="https://662370747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3VoWwSsyrEg0DEvIIjv9%2Fuploads%2Fgit-blob-836d8aaf00689baaf5b4e5bb59adf9a6e8ef558b%2FScreenshot%202024-02-29%20012538.png?alt=media" alt="" width="431"><figcaption></figcaption></figure></div>

{% tabs %}
{% tab title="Python" %}

```python
import requests
API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/&#x3C;chatlfowid>"

def query(payload):
    response = requests.post(API_URL, json=payload)
    return response.json()
    
output = query({
    "uploads": [
        {
            "data": 'data:audio/webm;codecs=opus;base64,GkXf', #base64 string
            "type": 'audio',
            "name": 'audio.wav',
            "mime": 'audio/webm'
        }
    ]
})
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/prediction/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "uploads": [
        {
            "data": 'data:audio/webm;codecs=opus;base64,GkXf', //base64 string
            "type": 'audio',
            "name": 'audio.wav',
            "mime": 'audio/webm'
        }
    ]
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Authentication

You can assign an API key to the prediction API from the UI. Refer [chatflow-level](https://tailwindsdocs.innovativesol.com/readme/api/chatflow-level "mention") for more details.

The Authorization header must be provided with the correct API key specified during a HTTP call.

```json
"Authorization": "Bearer <your-api-key>"
```

## 2. Vector Upsert API

* POST `/api/v1/vector/upsert/{your-chatflowid}`

Request Body

<table><thead><tr><th width="192">Key</th><th width="559">Description</th><th>Type</th><th>Required</th></tr></thead><tbody><tr><td>overrideConfig</td><td>Override existing flow configuration</td><td>object</td><td>No</td></tr><tr><td>stopNodeId</td><td>Node ID of the vector store. When you have multiple vector stores in a flow, you might not want to upsert all of them. Specifying <code>stopNodeId</code> will ensure only that specific vector store node is upserted.</td><td>array</td><td>No</td></tr></tbody></table>

### Document Loaders with Upload

Some document loaders in Tailwinds allow user to upload files:

<figure><img src="https://662370747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3VoWwSsyrEg0DEvIIjv9%2Fuploads%2Fgit-blob-55272b561a7f64d0335c11eb4fc2f0e73bcf1b45%2Fimage%20(2)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1)%20(1).png?alt=media" alt=""><figcaption></figcaption></figure>

If the flow contains [Document Loaders](https://tailwindsdocs.innovativesol.com/readme/chatflows/langchain/document-loaders) with Upload File functionality, the API looks slightly different. Instead of passing body as **JSON**, **form-data** is being used. This allows you to upload any files to the API.

{% hint style="info" %}
It is user's responsibility to make sure the file type is compatible with the expected file type from document loader. For example, if a Text File Loader is being used, you should only upload file with `.txt` extension.
{% endhint %}

{% tabs %}
{% tab title="Python" %}

```python
import requests

API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/vector/upsert/<chatlfowid>"

# use form data to upload files
form_data = {
    "files": ('state_of_the_union.txt', open('state_of_the_union.txt', 'rb'))
}

body_data = {
    "returnSourceDocuments": True
}

def query(form_data):
    response = requests.post(API_URL, files=form_data, data=body_data)
    print(response)
    return response.json()

output = query(form_data)
print(output)
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
// use FormData to upload files
let formData = new FormData();
formData.append("files", input.files[0]);
formData.append("returnSourceDocuments", true);

async function query(formData) {
    const response = await fetch(
        "http://localhost:3000/api/v1/vector/upsert/<chatlfowid>",
        {
            method: "POST",
            body: formData
        }
    );
    const result = await response.json();
    return result;
}

query(formData).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Document Loaders without Upload

For other [Document Loaders](https://tailwindsdocs.innovativesol.com/readme/chatflows/langchain/document-loaders) nodes without Upload File functionality, the API body is in **JSON** format similar to [Prediction API](#prediction-api).

{% tabs %}
{% tab title="Python" %}

```python
import requests

API_URL = "http://<yourtenant>.tailwinds.innovativesol.com/api/v1/vector/upsert/<chatlfowid>"

def query(form_data):
    response = requests.post(API_URL, json=payload)
    print(response)
    return response.json()

output = query({
    "overrideConfig": { # optional
        "returnSourceDocuments": true
    }
})
print(output)
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
async function query(data) {
    const response = await fetch(
        "http://localhost:3000/api/v1/vector/upsert/<chatlfowid>",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(data)
        }
    );
    const result = await response.json();
    return result;
}

query({
    "overrideConfig": { // optional
        "returnSourceDocuments": true
    }
}).then((response) => {
    console.log(response);
});
```

{% endtab %}
{% endtabs %}

### Authentication

You can assign an API key to the prediction API from the UI. Refer [chatflow-level](https://tailwindsdocs.innovativesol.com/readme/api/chatflow-level "mention") for more details.

The Authorization header must be provided with the correct API key specified during a HTTP call.

```json
"Authorization": "Bearer <your-api-key>"
```

## 3. Message API

* GET `/api/v1/chatmessage/{your-chatflowid}`
* DELETE `/api/v1/chatmessage/{your-chatflowid}`

Query Parameters

| Param     | Type   | Value       |
| --------- | ------ | ----------- |
| sessionId | string |             |
| sort      | enum   | ASC or DESC |
| startDate | string |             |
| endDate   | string |             |

### Authentication

Message API is restricted to only Tailwinds admin user. Basic authentication must be provided in the headers if Tailwinds instance has been configured with `USERNAME` and `PASSWORD`. Refer [https://github.com/innovativeSol/tailwinds-docs/blob/main/using-tailwinds/broken-reference/README.md](https://github.com/innovativeSol/tailwinds-docs/blob/main/using-tailwinds/broken-reference/README.md "mention") for more details.

{% tabs %}
{% tab title="Node" %}

```javascript
"Authorization": "Basic " + Buffer.from(username + ":" + password).toString('base64')
```

{% endtab %}

{% tab title="Browser" %}

```javascript
'"Authorization": "Basic " + btoa(username + ":" + password)
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

from requests.auth import HTTPBasicAuth
res = requests.get('http://<yourtenant>.tailwinds.innovativesol.com/api/v1/chatmessage/{your-chatflowid}', auth=HTTPBasicAuth(username, password))
```

{% endtab %}
{% endtabs %}
