Tutorial

Query & Retrieval

The Synvo API provides powerful query processing and intelligent file retrieval capabilities. These endpoints enable semantic search across your documents and conversational interactions with your data.

Authentication

All endpoints require authentication via either:

  • Bearer Token: Authorization: Bearer <token>
  • API Key: X-API-Key: <api_key>

Base URL

https://api.synvo.ai

Submit Query

Sends a message for processing and receives an intelligent response. Supports streaming, file search, web search, and various processing modes.

Endpoint: POST /ai/query

Content-Type: multipart/form-data

Parameters

ParameterTypeRequiredDefaultDescription
payloadstringYes-JSON string with messages array
modelstringNo"synvo"Model to use (synvo, gpt, etc.)
agent_modelstringNo"gpt"Agent model for tool use
parent_cuidstringNo-Parent conversation ID for threading
streamingbooleanNofalseEnable streaming responses
force_searchbooleanNofalseForce file search
mcpbooleanNofalseEnable web search
agentbooleanNofalseEnable deep research mode
profilingbooleanNofalseEnable performance profiling
model_argsstringNo-JSON string containing model specific args
platformstringNo"web"Platform identifier (web, api, mobile)

Payload Format

The payload parameter should be a JSON string containing a messages array:

{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Your question here"
        }
      ]
    }
  ]
}

Message Roles

  • system - System instructions
  • user - User messages
  • assistant - Assistant responses
  • tool - Tool execution results

Content Types

  • text - Plain text content
  • file - File attachments with file_id and path

Example Request

curl -X POST "https://api.synvo.ai/ai/query" \
  -H "X-API-Key: ${API-KEY}" \
  -F 'payload={"messages":[{"role":"user","content":[{"type":"text","text":"What is the capital of France?"}]}]}' \
  -F "model=synvo" \
  -F "streaming=false"
import requests
import json

token = "<BEARER_TOKEN>"
url = "https://api.synvo.ai/ai/query"
headers = {"X-API-Key": f"{token}"}

payload = {
    "messages": [
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "What is the capital of France?"}
            ]
        }
    ]
}

data = {
    "payload": json.dumps(payload),
    "model": "synvo",
    "streaming": "false"
}

response = requests.post(url, data=data, headers=headers, timeout=60)
response.raise_for_status()
print(response.json())
const token = "<BEARER_TOKEN>";

const payload = {
  messages: [
    {
      role: "user",
      content: [
        { type: "text", text: "What is the capital of France?" }
      ]
    }
  ]
};

const formData = new FormData();
formData.append("payload", JSON.stringify(payload));
formData.append("model", "synvo");
formData.append("streaming", "false");

const response = await fetch("https://api.synvo.ai/ai/query", {
  method: "POST",
  headers: {
    "X-API-Key": `${token}`,
  },
  body: formData,
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

{
  "success": true,
  "response": {
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "text": "The capital of France is Paris."
      }
    ],
    "cuid": "msg_abc123xyz",
    "created_at": "2024-01-15T10:30:00Z"
  },
  "suid": "sess_def456uvw",
  "summary": "Question about French capital",
  "timestamp": "2024-01-15T10:30:00Z"
}

Streaming Response

When streaming=true, the response is sent as Server-Sent Events (SSE):

Content-Type: text/event-stream

data: {"type": "token", "content": "The"}

data: {"type": "token", "content": " capital"}

data: {"type": "token", "content": " of"}

data: {"type": "done", "response": {...}}

Response Codes

  • 200 - Query processed successfully
  • 400 - Bad request (invalid payload or parameters)
  • 401 - Unauthorized

Search Files

Uses intelligent search to find files relevant to a query and returns file information.

Endpoint: POST /ai/search

Content-Type: application/x-www-form-urlencoded

Parameters

ParameterTypeRequiredDescription
messagestringYesSearch query

Example Request

curl -X POST "https://api.synvo.ai/ai/search" \
  -H "X-API-Key: ${API-KEY}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "message=financial reports for Q4"
import requests

token = "<BEARER_TOKEN>"
url = "https://api.synvo.ai/ai/search"
data = {"message": "financial reports for Q4"}
headers = {"X-API-Key": f"{token}"}

response = requests.post(url, data=data, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const token = "<BEARER_TOKEN>";
const params = new URLSearchParams({
  message: "financial reports for Q4"
});

const response = await fetch("https://api.synvo.ai/ai/search", {
  method: "POST",
  headers: {
    "X-API-Key": `${token}`,
  },
  body: params,
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

console.log(await response.json());

Example Response

[
  {
    "file_id": "abc123xyz",
    "file_path": "/reports/q4-financial.pdf",
    "file_name": "q4-financial.pdf",
    "file_type": "application/pdf",
    "created_at": "2024-01-15T10:30:00Z"
  },
  {
    "file_id": "def456uvw",
    "file_path": "/reports/q4-summary.docx",
    "file_name": "q4-summary.docx",
    "file_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "created_at": "2024-01-14T15:45:00Z"
  }
]

Response Codes

  • 200 - Search completed successfully
  • 401 - Unauthorized

Advanced Features

Conversation Threading

Use parent_cuid to continue existing conversations:

{
  "payload": "{\"messages\": [...]}",
  "parent_cuid": "msg_previous123"
}

File Context

Include files in your queries by adding file content to messages:

{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Analyze this document"
        },
        {
          "type": "file",
          "file_id": "abc123xyz",
          "path": "/documents/report.pdf"
        }
      ]
    }
  ]
}

Web Search Mode

Enable web search with mcp=true to include external information:

{
  "payload": "{\"messages\": [...]}",
  "mcp": true
}

Deep Research Mode

Enable agent mode with agent=true for complex multi-step research:

{
  "payload": "{\"messages\": [...]}",
  "agent": true,
  "agent_model": "gpt"
}

Model Options

Available Models

  • synvo - Default Synvo model (recommended)
  • gpt - OpenAI GPT models
  • Custom models as configured

Model Arguments

Pass model-specific parameters via model_args:

{
  "model_args": "{\"temperature\": 0.7, \"max_tokens\": 1000}"
}

Integration Examples

Chat Interface

class SynvoChat:
    def __init__(self, api_key):
        self.api_key = api_key
        self.session_id = None
        self.conversation = []
    
    def send_message(self, text, streaming=False):
        self.conversation.append({
            "role": "user",
            "content": [{"type": "text", "text": text}]
        })
        
        payload = {"messages": self.conversation}
        data = {
            "payload": json.dumps(payload),
            "streaming": str(streaming).lower(),
            "parent_cuid": self.session_id
        }
        
        response = requests.post(
            "https://api.synvo.ai/ai/query",
            data=data,
            headers={"X-API-Key": self.api_key}
        )
        
        result = response.json()
        self.session_id = result.get("suid")
        self.conversation.append(result["response"])
        
        return result["response"]["content"][0]["text"]

# Usage
chat = SynvoChat("your-api-key")
response = chat.send_message("Hello, how are you?")
print(response)
class SynvoChat {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.sessionId = null;
    this.conversation = [];
  }
  
  async sendMessage(text, streaming = false) {
    this.conversation.push({
      role: "user",
      content: [{ type: "text", text }]
    });
    
    const formData = new FormData();
    formData.append("payload", JSON.stringify({
      messages: this.conversation
    }));
    formData.append("streaming", streaming.toString());
    
    if (this.sessionId) {
      formData.append("parent_cuid", this.sessionId);
    }
    
    const response = await fetch("https://api.synvo.ai/ai/query", {
      method: "POST",
      headers: {
        "X-API-Key": this.apiKey
      },
      body: formData
    });
    
    const result = await response.json();
    this.sessionId = result.suid;
    this.conversation.push(result.response);
    
    return result.response.content[0].text;
  }
}

// Usage
const chat = new SynvoChat("your-api-key");
const response = await chat.sendMessage("Hello, how are you?");
console.log(response);

Document Analysis

def analyze_document(api_key, file_id, question):
    """Analyze a document with a specific question"""
    
    payload = {
        "messages": [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": question},
                    {"type": "file", "file_id": file_id}
                ]
            }
        ]
    }
    
    data = {
        "payload": json.dumps(payload),
        "force_search": "true"
    }
    
    response = requests.post(
        "https://api.synvo.ai/ai/query",
        data=data,
        headers={"X-API-Key": api_key}
    )
    
    return response.json()["response"]["content"][0]["text"]

# Usage
result = analyze_document(
    "your-api-key",
    "file123",
    "What are the key findings in this report?"
)
print(result)
async function analyzeDocument(apiKey, fileId, question) {
  const payload = {
    messages: [
      {
        role: "user",
        content: [
          { type: "text", text: question },
          { type: "file", file_id: fileId }
        ]
      }
    ]
  };
  
  const formData = new FormData();
  formData.append("payload", JSON.stringify(payload));
  formData.append("force_search", "true");
  
  const response = await fetch("https://api.synvo.ai/ai/query", {
    method: "POST",
    headers: {
      "X-API-Key": apiKey
    },
    body: formData
  });
  
  const result = await response.json();
  return result.response.content[0].text;
}

// Usage
const result = await analyzeDocument(
  "your-api-key",
  "file123",
  "What are the key findings in this report?"
);
console.log(result);

Best Practices

Query Optimization

  1. Be Specific: Use clear, specific queries for better results
  2. Context Length: Keep conversations focused to avoid context limits
  3. File References: Include relevant files when asking document-specific questions

Performance Tips

  1. Streaming: Use streaming for long responses to improve user experience
  2. Model Selection: Choose appropriate models based on task complexity
  3. Search First: Use /ai/search to find relevant files before querying

Rate Limiting

  • Standard rate limits apply per API key
  • Streaming requests may have different limits
  • Monitor response headers for rate limit information

Error Handling

Common Error Responses

{
  "error": "Invalid payload format",
  "code": "INVALID_PAYLOAD"
}
{
  "error": "Model not available",
  "code": "MODEL_UNAVAILABLE"
}

Error Codes

  • INVALID_PAYLOAD - Malformed JSON in payload parameter
  • MODEL_UNAVAILABLE - Requested model is not available
  • RATE_LIMITED - Too many requests
  • CONTEXT_TOO_LONG - Message context exceeds limits
  • SEARCH_FAILED - File search operation failed

Handling Query Errors

def safe_query(api_key, payload, max_retries=3):
    """Safely perform query with error handling"""
    for attempt in range(max_retries):
        try:
            data = {
                "payload": json.dumps(payload),
                "model": "synvo"
            }
            
            response = requests.post(
                "https://api.synvo.ai/ai/query",
                data=data,
                headers={"X-API-Key": api_key},
                timeout=60
            )
            response.raise_for_status()
            return response.json()
            
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 400:
                error_data = e.response.json()
                if error_data.get("code") == "INVALID_PAYLOAD":
                    print("Invalid payload format")
                    return None
            elif e.response.status_code == 429:
                print(f"Rate limited, retrying in {2**attempt} seconds...")
                time.sleep(2**attempt)
                continue
            else:
                print(f"Query failed: {e}")
                return None
        except Exception as e:
            print(f"Unexpected error: {e}")
            if attempt < max_retries - 1:
                time.sleep(2**attempt)
                continue
            return None

# Usage
payload = {
    "messages": [
        {
            "role": "user", 
            "content": [{"type": "text", "text": "Hello"}]
        }
    ]
}
result = safe_query("your-api-key", payload)
if result:
    print("Query successful")
async function safeQuery(apiKey, payload, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const formData = new FormData();
      formData.append("payload", JSON.stringify(payload));
      formData.append("model", "synvo");
      
      const response = await fetch("https://api.synvo.ai/ai/query", {
        method: "POST",
        headers: { "X-API-Key": apiKey },
        body: formData
      });
      
      if (!response.ok) {
        if (response.status === 400) {
          const errorData = await response.json();
          if (errorData.code === "INVALID_PAYLOAD") {
            console.log("Invalid payload format");
            return null;
          }
        } else if (response.status === 429) {
          console.log(`Rate limited, retrying in ${2**attempt} seconds...`);
          await new Promise(resolve => setTimeout(resolve, (2**attempt) * 1000));
          continue;
        } else {
          throw new Error(`Request failed: ${response.status}`);
        }
      }
      
      return await response.json();
      
    } catch (error) {
      console.log(`Query error (attempt ${attempt + 1}): ${error.message}`);
      if (attempt < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, (2**attempt) * 1000));
        continue;
      }
      return null;
    }
  }
}

// Usage
const payload = {
  messages: [
    {
      role: "user",
      content: [{ type: "text", text: "Hello" }]
    }
  ]
};
const result = await safeQuery("your-api-key", payload);
if (result) {
  console.log("Query successful");
}

Streaming Implementation

Python Streaming

import requests
import json

def stream_query(api_key, payload):
    """Stream a query response"""
    data = {
        "payload": json.dumps(payload),
        "streaming": "true",
        "model": "synvo"
    }
    
    response = requests.post(
        "https://api.synvo.ai/ai/query",
        data=data,
        headers={"X-API-Key": api_key},
        stream=True
    )
    
    for line in response.iter_lines():
        if line:
            line = line.decode('utf-8')
            if line.startswith('data: '):
                try:
                    data = json.loads(line[6:])
                    if data.get("type") == "token":
                        print(data["content"], end="", flush=True)
                    elif data.get("type") == "done":
                        print("\n\nStream complete!")
                        return data["response"]
                except json.JSONDecodeError:
                    continue

# Usage
payload = {
    "messages": [
        {
            "role": "user",
            "content": [{"type": "text", "text": "Tell me a story"}]
        }
    ]
}
stream_query("your-api-key", payload)

JavaScript Streaming

async function streamQuery(apiKey, payload) {
  const formData = new FormData();
  formData.append("payload", JSON.stringify(payload));
  formData.append("streaming", "true");
  formData.append("model", "synvo");
  
  const response = await fetch("https://api.synvo.ai/ai/query", {
    method: "POST",
    headers: { "X-API-Key": apiKey },
    body: formData
  });
  
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    const chunk = decoder.decode(value);
    const lines = chunk.split('\n');
    
    for (const line of lines) {
      if (line.startsWith('data: ')) {
        try {
          const data = JSON.parse(line.slice(6));
          if (data.type === "token") {
            process.stdout.write(data.content);
          } else if (data.type === "done") {
            console.log("\n\nStream complete!");
            return data.response;
          }
        } catch (e) {
          // Skip invalid JSON
        }
      }
    }
  }
}

// Usage
const payload = {
  messages: [
    {
      role: "user",
      content: [{ type: "text", text: "Tell me a story" }]
    }
  ]
};
await streamQuery("your-api-key", payload);