EvidenceHunt API Documentation

Welcome to the EvidenceHunt API!

Table of Contents


Quick Start

Get started with the EvidenceHunt API in 3 simple steps:

1. Get Your API Key

2. Make Your First Request

curl -X POST https://evidencehunt.com/api/v1/query \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/vnd.evidencehunt.chat-stream+json" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is the efficacy of metformin for type 2 diabetes?",
    "sources": ["pubmed"]
  }'

3. Process the Streaming Response

The API returns a streaming response with newline-delimited JSON events. Each line is a separate JSON object representing a different event type.


Authentication

EvidenceHunt API supports two authentication methods:

API Key Authentication (Recommended for API access)

Include your API key in the request header:

X-API-Key: your_api_key_here

How to get an API key:

  1. Sign in to your EvidenceHunt account
  2. Navigate to https://evidencehunt.com/api-keys
  3. Click "Create New API Key"
  4. Copy and securely store your key

Bearer Token Authentication (Web application only)

For web applications, you can use JWT authentication:

Authorization: Bearer your_jwt_token

Note: Bearer tokens are primarily used by the EvidenceHunt web application. API integrations should use API Key authentication.


Base URL

Production:

https://evidencehunt.com

Local Development:

http://localhost:8080

Endpoints

POST /api/v1/query

Execute a research query against EvidenceHunt's evidence database to get AI-powered answers backed by scientific literature.

Endpoint:

POST /api/v1/query

Required Headers:

X-API-Key: your_api_key_here
Accept: application/vnd.evidencehunt.chat-stream+json
Content-Type: application/json

Request Body:

{
  "question": "What is the efficacy of metformin for type 2 diabetes?",
  "sources": ["pubmed"],
  "chatElaborateMode": false,
  "followUp": false,
  "userLanguage": "en"
}

Request Parameters

Required Parameters

Parameter Type Description
question string Your research question (max 1000 tokens)

Optional Parameters

Parameter Type Default Description
sources array ["pubmed"] Public data sources to search. Only "pubmed" is supported
customDocuments array [] Array of custom organization folder UUIDs to search
chatElaborateMode boolean false Enable for more detailed, comprehensive answers (+1 credit, only when PubMed is included)
followUp boolean false Set to true when asking a follow-up question (+1 credit)
outputId string - Required when followUp is true. Use the output_id from previous response
outputFormat string - Custom formatting instructions for the answer. By default, responses use Markdown formatting. Use this to change structure, disable Markdown, or customize the output style (no additional credits)
userLanguage string "en" Language code for the answer (see supported languages below)

Supported Languages

The API supports responses in 50+ languages. Use the ISO language code in the userLanguage parameter:

Code Language Code Language Code Language
en English es Spanish fr French
de German zh Chinese ja Japanese
ko Korean ar Arabic ru Russian
pt Portuguese it Italian nl Dutch
pl Polish tr Turkish vi Vietnamese
th Thai sv Swedish hi Hindi

For the complete list of supported languages, see the Language Codes section.


Response Format

The API returns a streaming response with newline-delimited JSON events. Each line is a separate JSON object with a type field.

Response Headers

X-Credits-Used: 1
X-Credits-Remaining: 99

Event Types

1. all_docs - Scientific Articles

Sent first, contains all retrieved scientific articles.

{
  "type": "all_docs",
  "docs": [
    {
      "id": "12345",
      "title": "Metformin efficacy in Type 2 Diabetes",
      "abstract": "This randomized controlled trial demonstrates...",
      "authors": ["Smith J", "Johnson A"],
      "year": 2023,
      "journal": "Diabetes Care",
      "doi": "10.1234/dc23-0001"
    }
  ]
}

2. answer_part - Answer Chunks

Sent multiple times as the answer is being generated. The text is formatted in Markdown by default.

{
  "type": "answer_part",
  "text": "Metformin is highly effective ",
  "index": 0
}

3. output_done - Complete Answer

Sent at the end with the complete answer and output ID. The answer is formatted in Markdown by default (unless customized with outputFormat).

{
  "type": "output_done",
  "answer": "Metformin is highly effective for managing type 2 diabetes. Studies show...",
  "output_id": "abc-123-xyz"
}

4. error - Error Message

Sent if an error occurs during processing.

{
  "type": "error",
  "message": "Failed to process query"
}

5. failed - Query Failed

Sent if the query completely fails.

{
  "type": "failed",
  "reason": "Unable to retrieve documents"
}

Example Stream

{"type":"all_docs","docs":[{"id":"12345","title":"Metformin in T2D"}]}
{"type":"answer_part","text":"Metformin is ","index":0}
{"type":"answer_part","text":"highly effective ","index":1}
{"type":"answer_part","text":"for type 2 diabetes.","index":2}
{"type":"output_done","answer":"Metformin is highly effective for type 2 diabetes.","output_id":"abc-123"}

Credits System

Each API query consumes credits based on the features used:

Feature Credits
Base query 1 credit
Elaborate mode (chatElaborateMode: true) +1 credit*
Follow-up question (followUp: true) +1 credit
Multiple sources (2+ data sources) +1 credit
Custom answer formatting (outputFormat) 0 credits (free)
Maximum per query 4 credits

Important Notes:

Examples

Checking Your Credit Balance

After each request, check the response headers:


Error Handling

The API uses standard HTTP status codes and returns JSON error responses.

Status Codes

Code Meaning Description
200 Success Request successful, streaming response
400 Bad Request Invalid input or missing required fields
401 Unauthorized Invalid or missing API key
402 Payment Required Insufficient credits
403 Forbidden No access to requested sources
500 Internal Server Error Server error occurred

Error Response Format

{
  "error": "Error message description"
}

Common Errors

400 Bad Request

Invalid Accept Header:

{
  "error": "Provided content type in Accept header is not supported."
}

Missing Required Field:

{
  "error": "question is required"
}

Token Limit Exceeded:

{
  "error": "Question exceeds maximum token limit of 1000 tokens (current: 1523 tokens)"
}

Invalid Source:

{
  "error": "\"sources[0]\" must be [pubmed]"
}

Invalid UUID:

{
  "error": "Invalid UUID format: \"not-a-uuid\". Custom document IDs must be valid UUIDs."
}

Invalid Output ID:

{
  "error": "Failed to retrieve conversation history. The output_id may be invalid or expired."
}

401 Unauthorized

{
  "error": "Invalid API key"
}

402 Payment Required

{
  "error": "Insufficient credits",
  "required": 2,
  "balance": 0
}

403 Forbidden

{
  "error": "You don't have access to the requested sources"
}

Code Examples

JavaScript/Node.js

Using Fetch (Modern Node.js 18+):

const API_KEY = 'your_api_key_here';

async function queryEvidenceHunt(question) {
  const response = await fetch('https://evidencehunt.com/api/v1/query', {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Accept': 'application/vnd.evidencehunt.chat-stream+json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      question: question,
      sources: ['pubmed']
    })
  });

  // Check credits
  console.log('Credits Used:', response.headers.get('X-Credits-Used'));
  console.log('Credits Remaining:', response.headers.get('X-Credits-Remaining'));

  // Process streaming response
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let fullAnswer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop(); // Keep incomplete line in buffer

    for (const line of lines) {
      if (line.trim()) {
        const event = JSON.parse(line);

        switch (event.type) {
          case 'all_docs':
            console.log(`\nRetrieved ${event.docs.length} documents`);
            break;

          case 'answer_part':
            process.stdout.write(event.text);
            fullAnswer += event.text;
            break;

          case 'output_done':
            console.log(`\n\nOutput ID: ${event.output_id}`);
            return {
              answer: event.answer,
              outputId: event.output_id
            };

          case 'error':
            console.error(`\nError: ${event.message}`);
            break;
        }
      }
    }
  }
}

// Usage
queryEvidenceHunt('What is the efficacy of metformin for type 2 diabetes?')
  .then(result => {
    console.log('\nQuery completed!');
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

Using HTTP Module (Node.js):

const http = require('http');
const https = require('https');

const API_KEY = 'your_api_key_here';

function queryEvidenceHunt(question) {
  const data = JSON.stringify({
    question: question,
    sources: ['pubmed']
  });

  const options = {
    hostname: 'evidencehunt.com',
    port: 443,
    path: '/api/v1/query',
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Accept': 'application/vnd.evidencehunt.chat-stream+json',
      'Content-Type': 'application/json',
      'Content-Length': data.length
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      console.log(`Status: ${res.statusCode}`);
      console.log(`Credits Used: ${res.headers['x-credits-used']}`);
      console.log(`Credits Remaining: ${res.headers['x-credits-remaining']}`);

      let buffer = '';
      let outputId = null;

      res.on('data', (chunk) => {
        buffer += chunk.toString();
        const lines = buffer.split('\n');
        buffer = lines.pop();

        lines.forEach(line => {
          if (line.trim()) {
            const event = JSON.parse(line);

            if (event.type === 'all_docs') {
              console.log(`\nRetrieved ${event.docs.length} documents\n`);
            } else if (event.type === 'answer_part') {
              process.stdout.write(event.text);
            } else if (event.type === 'output_done') {
              outputId = event.output_id;
            }
          }
        });
      });

      res.on('end', () => {
        console.log(`\n\nOutput ID: ${outputId}`);
        resolve(outputId);
      });
    });

    req.on('error', reject);
    req.write(data);
    req.end();
  });
}

// Usage
queryEvidenceHunt('What is the efficacy of metformin for type 2 diabetes?')
  .catch(console.error);

Python

Using Requests Library:

import requests
import json

API_KEY = "your_api_key_here"

def query_evidencehunt(question):
    """Query EvidenceHunt API and print streaming response."""

    url = "https://evidencehunt.com/api/v1/query"

    headers = {
        "X-API-Key": API_KEY,
        "Accept": "application/vnd.evidencehunt.chat-stream+json",
        "Content-Type": "application/json"
    }

    payload = {
        "question": question,
        "sources": ["pubmed"],
        "chatElaborateMode": True
    }

    response = requests.post(url, headers=headers, json=payload, stream=True)

    # Check credits
    print(f"Credits Used: {response.headers.get('X-Credits-Used')}")
    print(f"Credits Remaining: {response.headers.get('X-Credits-Remaining')}\n")

    if response.status_code != 200:
        error_data = response.json()
        print(f"Error: {error_data.get('error')}")
        return None

    # Process streaming response
    full_answer = ""
    output_id = None

    for line in response.iter_lines():
        if line:
            event = json.loads(line.decode('utf-8'))

            if event.get("type") == "all_docs":
                docs = event.get("docs", [])
                print(f"Retrieved {len(docs)} documents\n")

            elif event.get("type") == "answer_part":
                text = event.get("text", "")
                print(text, end="", flush=True)
                full_answer += text

            elif event.get("type") == "output_done":
                output_id = event.get("output_id")
                full_answer = event.get("answer")
                print(f"\n\nOutput ID: {output_id}")

            elif event.get("type") == "error":
                print(f"\nError: {event.get('message')}")

    return {
        "answer": full_answer,
        "output_id": output_id
    }

# Usage
if __name__ == "__main__":
    result = query_evidencehunt(
        "What is the efficacy of metformin for type 2 diabetes?"
    )

    if result:
        print("\n\nQuery completed successfully!")

Follow-up Question Example:

# First query
result1 = query_evidencehunt("What is metformin?")

# Follow-up query using output_id
if result1 and result1.get("output_id"):
    url = "https://evidencehunt.com/api/v1/query"

    headers = {
        "X-API-Key": API_KEY,
        "Accept": "application/vnd.evidencehunt.chat-stream+json",
        "Content-Type": "application/json"
    }

    payload = {
        "question": "What are the common side effects?",
        "sources": ["pubmed"],
        "followUp": True,
        "outputId": result1["output_id"]
    }

    response = requests.post(url, headers=headers, json=payload, stream=True)
    # Process response...

cURL

Basic Query:

curl -X POST https://evidencehunt.com/api/v1/query \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/vnd.evidencehunt.chat-stream+json" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is the efficacy of metformin for type 2 diabetes?",
    "sources": ["pubmed"]
  }'

Elaborate Mode:

curl -X POST https://evidencehunt.com/api/v1/query \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/vnd.evidencehunt.chat-stream+json" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Compare statins vs fibrates for dyslipidemia",
    "sources": ["pubmed"],
    "chatElaborateMode": true
  }'

Include Response Headers:

curl -i -X POST https://evidencehunt.com/api/v1/query \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/vnd.evidencehunt.chat-stream+json" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is metformin?",
    "sources": ["pubmed"]
  }'

TypeScript

With Type Definitions:

interface QueryRequest {
  question: string;
  sources?: string[];
  customDocuments?: string[];
  chatElaborateMode?: boolean;
  followUp?: boolean;
  outputId?: string;
  userLanguage?: string;
}

interface StreamEvent {
  type: 'all_docs' | 'answer_part' | 'output_done' | 'error' | 'failed';
  docs?: Array<{
    id: string;
    title: string;
    abstract: string;
    authors?: string[];
    year?: number;
    journal?: string;
    doi?: string;
  }>;
  text?: string;
  index?: number;
  answer?: string;
  output_id?: string;
  message?: string;
  reason?: string;
}

interface QueryResult {
  answer: string;
  outputId: string;
  documents?: any[];
}

class EvidenceHuntAPI {
  private apiKey: string;
  private baseUrl: string;

  constructor(apiKey: string, baseUrl = 'https://evidencehunt.com') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  async query(request: QueryRequest): Promise<QueryResult> {
    const response = await fetch(`${this.baseUrl}/api/v1/query`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Accept': 'application/vnd.evidencehunt.chat-stream+json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        sources: ['pubmed'],
        ...request
      })
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error || 'Query failed');
    }

    // Log credits
    console.log('Credits Used:', response.headers.get('X-Credits-Used'));
    console.log('Credits Remaining:', response.headers.get('X-Credits-Remaining'));

    // Process stream
    const reader = response.body!.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    let result: QueryResult = { answer: '', outputId: '' };

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.trim()) {
          const event: StreamEvent = JSON.parse(line);

          switch (event.type) {
            case 'all_docs':
              result.documents = event.docs;
              console.log(`\nRetrieved ${event.docs?.length || 0} documents`);
              break;

            case 'answer_part':
              process.stdout.write(event.text || '');
              result.answer += event.text || '';
              break;

            case 'output_done':
              result.answer = event.answer || result.answer;
              result.outputId = event.output_id || '';
              console.log(`\n\nOutput ID: ${result.outputId}`);
              break;

            case 'error':
              throw new Error(event.message || 'Unknown error');
          }
        }
      }
    }

    return result;
  }

  async followUp(question: string, outputId: string): Promise<QueryResult> {
    return this.query({
      question,
      followUp: true,
      outputId
    });
  }
}

// Usage
const api = new EvidenceHuntAPI('your_api_key_here');

(async () => {
  try {
    const result = await api.query({
      question: 'What is the efficacy of metformin for type 2 diabetes?',
      chatElaborateMode: false
    });

    console.log('\n\nQuery completed!');

    // Ask follow-up
    if (result.outputId) {
      const followUp = await api.followUp(
        'What are the common side effects?',
        result.outputId
      );
    }
  } catch (error) {
    console.error('Error:', error);
  }
})();

Advanced Features

Follow-up Questions

Continue a conversation by asking follow-up questions. The AI will maintain context from previous queries.

How it works:

  1. Make your first query and save the output_id from the output_done event
  2. Make a second query with followUp: true and include the outputId

Example:

// First query
const response1 = await fetch('https://evidencehunt.com/api/v1/query', {
  method: 'POST',
  headers: {
    'X-API-Key': API_KEY,
    'Accept': 'application/vnd.evidencehunt.chat-stream+json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    question: 'What is metformin?',
    sources: ['pubmed']
  })
});

// Extract output_id from output_done event
let outputId = '...'; // From output_done event

// Follow-up query
const response2 = await fetch('https://evidencehunt.com/api/v1/query', {
  method: 'POST',
  headers: {
    'X-API-Key': API_KEY,
    'Accept': 'application/vnd.evidencehunt.chat-stream+json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    question: 'What are the common side effects?',
    sources: ['pubmed'],
    followUp: true,
    outputId: outputId
  })
});

Cost: +1 credit per follow-up question


Custom Documents

Search your organization's private documents in addition to public sources like PubMed.

Requirements:

Example:

{
  "question": "What are our internal treatment guidelines?",
  "sources": ["pubmed"],
  "customDocuments": ["550e8400-e29b-41d4-a716-446655440000"]
}

Notes:


Elaborate Mode

Get more detailed, comprehensive answers with additional context and explanations.

Enable elaborate mode:

{
  "question": "Compare statins vs fibrates for dyslipidemia",
  "sources": ["pubmed"],
  "chatElaborateMode": true
}

Benefits:

Cost: +1 credit only when PubMed is included as a source

Important:


Custom Answer Formatting

Default Behavior: By default, all API responses are formatted in Markdown. This includes headings, lists, tables, bold/italic text, and other Markdown formatting elements to make the content structured and readable.

Customizing the Format: You can customize how the AI formats its response by providing specific formatting instructions using the outputFormat parameter. This feature is free and does not consume additional credits.

Use outputFormat to:

Example - Request a table format:

{
  "question": "What are the main side effects of metformin?",
  "sources": ["pubmed"],
  "outputFormat": "Format the answer as a table with columns: Side Effect, Frequency, Severity"
}

Example - Request bullet points:

{
  "question": "What are treatment options for hypertension?",
  "sources": ["pubmed"],
  "outputFormat": "Translate into plain, patient-friendly language for use in a patient leaflet. Keep answers short, with bulletpoints and in simple educational tone."
}

Example - Request specific structure:

{
  "question": "Explain the mechanism of action of aspirin",
  "sources": ["pubmed"],
  "outputFormat": "Structure the answer with these sections: 1) Mechanism 2) Clinical Effects 3) Contraindications"
}

Example - Disable Markdown formatting:

{
  "question": "What is the recommended dosage of aspirin for cardiovascular protection?",
  "sources": ["pubmed"],
  "outputFormat": "Provide the answer in plain text without any markdown formatting, bold, or italics"
}

Notes:

Cost: Free (0 credits)


Multi-language Support

Get answers in 50+ languages by setting the userLanguage parameter.

Example:

{
  "question": "Was ist die Wirksamkeit von Metformin bei Typ-2-Diabetes?",
  "sources": ["pubmed"],
  "userLanguage": "de"
}

Supported Languages:

Language Code Language Code Language Code
Albanian sq Arabic ar Belarusian be
Bengali bn Bosnian bs Bulgarian bg
Chinese zh Chinese (Traditional) zh-TW Croatian hr
Czech cs Danish da Dutch nl
English en Esperanto eo Estonian et
Finnish fi French fr Frisian fy
Georgian ka German de Greek el
Hebrew he Hindi hi Hungarian hu
Icelandic is Indonesian id Italian it
Japanese ja Javanese jw Korean ko
Latvian lv Lithuanian lt Macedonian mk
Maltese mt Nepali ne Norwegian no
Persian fa Polish pl Portuguese pt
Romanian ro Russian ru Serbian sr
Slovenian sl Somali so Spanish es
Sundanese su Swahili sw Swedish sv
Thai th Turkish tr Ukrainian uk
Vietnamese vi

Rate Limits

Current rate limits:

Best Practices:


Support

Need help?

Common Questions:

Q: How do I get more credits? A: Visit your account dashboard to purchase additional credits or upgrade your plan.

Q: Can I use the API for commercial purposes? A: Yes! Please review our terms of service and contact us for enterprise plans.

Q: What happens if I exceed my credit limit? A: The API will return a 402 Payment Required error. Purchase more credits to continue.

Q: How long are output IDs valid for follow-up questions? A: Output IDs are valid for a limited time (typically 24 hours). If expired, you'll receive an error.

Q: Can I search sources other than PubMed? A: Currently, only PubMed is supported as a public source. Contact us about custom data sources for enterprise plans.


Last Updated: November 2025 API Version: 1.0.0