Developer documentationAPI + MCPRequest API access
API V2 / REFERENCE

AI research

Stream research answers grounded in company data.

Working inside your own AI client? See the MCP connection guide →

Use the AI research API to research an existing customer and investigate companies in its wider group. Supply the customer’s country, your offer and your territory when they matter to the question.

mode: ai

A streamed research answer

Use text events for the answer and tool_result events for the supporting data.

mode: data

Structured data for your app

Read collected tool outputs from the final done event. The transport is still SSE.

Ask an AI research question

#
POST/ai/query

Send a self-contained research question. AI research selects company-data tools and streams their results, with an optional written answer.

ParameterLocation / typeDescription
queryRequiredbodystringOne self-contained question; maximum 4,000 characters. No conversation history is stored by this endpoint.
modebodystringai streams prose and tool results; data returns tool results without prose. Default: ai.
cURL request
curl --no-buffer --request POST "https://api.globaldatabase.com/v2/ai/query" \
  --header "Authorization: Token $GLOBAL_DATABASE_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Accept: text/event-stream' \
  --data '{
  "query": "Find GLOBAL DATA INTELLIGENCE in GB and show its corporate group. Separate company facts from possible expansion questions.",
  "mode": "ai"
}'

Response

200 text/event-stream. Read frames incrementally until done or error; do not call response.json().

Integration notes
  • Each successful request uses one AI-query request. Underlying data-tool usage is metered separately.
  • For follow-ups, include only the relevant prior context in a new query and keep the complete string within 4,000 characters.
Provider reference ↗

Read the stream

AI research uses a POST request. Use fetch with a body reader rather than the browser’s GET-only EventSource interface. Network chunks are not complete events: buffer until the blank line between SSE frames.

EventPayload fieldsHow to use it
statusmessageProgress information.
tool_calltoolA data tool is about to run.
tool_resulttool, data, duration, is_errorA complete tool result; preserve its source context.
generatingtypeProse generation has started (ai mode).
textcontentAppend content in order (ai mode).
suggested_actionsactionsPossible follow-up questions (ai mode).
donetools_used, usage, message_id; data in data modeTerminal success. data mode carries collected {tool, data} entries.
errordetail, codeTerminal failure after the stream has started.
SSE · illustrative data-mode frames
event: tool_result
data: {"type":"tool_result","tool":"get_company_by_identifiers","data":{"id":29707645},"is_error":false}

event: done
data: {"type":"done","data":[{"tool":"get_company_by_identifiers","data":{"id":29707645}}],"tools_used":["get_company_by_identifiers"],"message_id":null}

Abbreviated frames showing the wire format. Tool payloads vary. Ignore comment keepalives and unknown future events; a closed connection without done is an incomplete response.

A complete server-side streaming example

This Node.js client handles split frames, UTF-8 decoding, HTTP errors, SSE errors and premature disconnection. The 120-second timeout and 5 MB frame cap are example application choices, not provider limits.

Download JavaScript client
JavaScript · complete streaming client
// Node.js 20+. Run on your server; never ship the API key to a browser.
import { pathToFileURL } from 'node:url';

export async function* readSSE(body) {
  const reader = body.getReader();
  const decoder = new TextDecoder();
  let pending = '';
  function parse(frame) {
    if (frame.length > 5_000_000) throw new Error('Application frame limit exceeded');
    const lines = frame.replace(/^\uFEFF/, '').split(/\r?\n/);
    const data = lines.filter(line => line.startsWith('data:')).map(line => line.slice(5).trimStart()).join('\n');
    if (!data) return;
    if (data === '[DONE]') return { type: 'done' };
    const value = JSON.parse(data);
    if (!value || typeof value !== 'object' || Array.isArray(value)) return;
    const type = lines.find(line => line.startsWith('event:'))?.slice(6).trim();
    return typeof value.type === 'string' ? value : type ? { ...value, type } : value;
  }
  try {
    while (true) {
      const { value, done } = await reader.read();
      pending += done ? decoder.decode() : decoder.decode(value, { stream: true });
      let boundary;
      while ((boundary = /\r?\n\r?\n/.exec(pending))) {
        const frame = pending.slice(0, boundary.index);
        pending = pending.slice(boundary.index + boundary[0].length);
        const event = parse(frame);
        if (event) yield event;
      }
      if (pending.length > 5_000_000) throw new Error('Application frame limit exceeded');
      if (done) { const event = parse(pending); if (event) yield event; break; }
    }
  } finally {
    await reader.cancel().catch(() => {});
    reader.releaseLock();
  }
}

export async function askCompanyResearch(query, mode = 'ai') {
  const key = process.env.GLOBAL_DATABASE_API_KEY;
  if (!key) throw new Error('Set GLOBAL_DATABASE_API_KEY on your server');
  if (typeof query !== 'string' || !query.trim() || [...query].length > 4000) {
    throw new Error('Supply a question of 1–4,000 characters');
  }
  if (!['ai', 'data'].includes(mode)) throw new Error('Mode must be ai or data');

  const response = await fetch('https://api.globaldatabase.com/v2/ai/query', {
    method: 'POST',
    headers: {
      Authorization: `Token ${key}`,
      'Content-Type': 'application/json',
      Accept: 'text/event-stream'
    },
    body: JSON.stringify({ query, mode }),
    signal: AbortSignal.timeout(120_000)
  });
  if (!response.ok) {
    const retryAfter = response.headers.get('Retry-After');
    throw new Error(`API HTTP ${response.status}; Retry-After: ${retryAfter ?? 'not supplied'}`);
  }
  if (!response.body || !response.headers.get('content-type')?.includes('text/event-stream')) {
    throw new Error('Expected a Server-Sent Events response');
  }
  let answer = '';
  for await (const event of readSSE(response.body)) {
    if (event.type === 'error') {
      throw new Error(`AI research stream error: ${event.code ?? 'unknown'}`);
    }
    if (event.type === 'text') {
      answer += event.content ?? '';
      process.stdout.write(event.content ?? '');
    }
    if (event.type === 'done') {
      return { answer, data: event.data ?? [], usage: event.usage };
    }
    // Handle status, tool_result and suggested_actions as needed.
    // Keep tool_result source metadata with any data used in your UI.
  }
  throw new Error('The stream ended before a done event; the response is incomplete');
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  const query = process.argv[2] || 'Find GLOBAL DATA INTELLIGENCE in GB and show its corporate group.';
  askCompanyResearch(query, process.argv[3] || 'ai')
    .then(result => console.log('\n', JSON.stringify(result, null, 2)))
    .catch(error => { console.error(error.message); process.exitCode = 1; });
}

Set GLOBAL_DATABASE_API_KEY, then run node ai-research-client.mjs. Add a quoted question and an optional data mode argument to customize the request.

Based on the Global Database API v2 reference ↗ · Reviewed 14 September 2026. Examples are illustrative or abbreviated, not live company reports.