Floreal Logo
SearchSearch Groups

Get status for all searches in a SearchGroup

Check the status of all searches within a search group

This endpoint returns the status and metadata for every search that belongs to a search group. Use it to monitor completion progress, check for errors, and get links to retrieve results for each completed search.


What is a Search Group?

A search group is a collection of searches that share the same searchGroupId. You can group multiple searches together to:

  • Track multiple related searches in one request
  • Monitor completion of parallel searches
  • Compare different algorithm results (dense vs sparse vs hybrid)
  • Organize searches by query or session

When to Use This Endpoint

Use this endpoint to:

  • ✅ Check if all searches in a group have completed
  • ✅ Monitor progress of multiple parallel searches
  • ✅ Get resultsUrl links for all completed searches
  • ✅ Identify failed searches and error messages
  • ✅ Track processing times across searches

Don't use this for:

  • ❌ Getting actual search results (use /searches/\{searchId\}/results instead)
  • ❌ Comparing result content (this only shows status, not results)

Response Structure

Example Response

{
  "searchGroupId": "e1de299b-8cb3-4d56-9f9b-fc58c8c59841",
  "groupStatus": "completed",
  "query": "ai engineer",
  "totalSearches": 2,
  "searches": [
    {
      "searchId": "4c4b15e0-032d-43e9-b41b-ef3a2efa2e84",
      "searchType": "dense",
      "status": "completed",
      "resultsCount": 2,
      "processingTimeMs": 1763,
      "error": null,
      "createdAt": "2025-11-04T14:21:55.139Z",
      "completedAt": "2025-11-04T14:21:58.018Z",
      "statusUrl": "/v1/public/searches/4c4b15e0-032d-43e9-b41b-ef3a2efa2e84",
      "resultsUrl": "/v1/public/searches/4c4b15e0-032d-43e9-b41b-ef3a2efa2e84/results"
    },
    {
      "searchId": "54153a24-c8e5-4eb6-997c-9a8d0f1216e2",
      "searchType": "dense",
      "status": "completed",
      "resultsCount": 2,
      "processingTimeMs": 351,
      "error": null,
      "createdAt": "2025-11-04T14:22:07.223Z",
      "completedAt": "2025-11-04T14:22:07.957Z",
      "statusUrl": "/v1/public/searches/54153a24-c8e5-4eb6-997c-9a8d0f1216e2",
      "resultsUrl": "/v1/public/searches/54153a24-c8e5-4eb6-997c-9a8d0f1216e2/results"
    }
  ],
  "summary": {
    "completed": 2,
    "processing": 0,
    "failed": 0
  }
}

Field Descriptions

Top-Level Fields

FieldTypeDescription
searchGroupIdUUIDThe group identifier
groupStatusstringOverall status of all searches in the group
querystringThe search query (same across all searches in group)
totalSearchesintegerTotal number of searches in this group
searchesarrayArray of individual search status objects
summaryobjectCount of searches by status

Group Status Values

StatusMeaningAction
initiatedAll searches are queued, none processing yetWait before polling
processingAt least one search is still runningPoll again until completed or partial
completedAll searches finished successfullyFetch results from each search
partialSome searches completed, others failedCheck individual search errors

Individual Search Object

Each search in the searches array contains:

FieldTypeDescription
searchIdUUIDUnique identifier for this specific search
searchTypestringAlgorithm used: dense, sparse, hybrid, or builtin-rerank
statusstringSearch status: initiated, processing, completed, or failed
resultsCountinteger/nullNumber of results found (null if not completed)
processingTimeMsinteger/nullProcessing time in milliseconds (null if not completed)
errorstring/nullError message if search failed (null if successful)
createdAtdatetimeWhen the search was initiated
completedAtdatetime/nullWhen the search finished (null if still running)
statusUrlstringDirect link to check this search's detailed status
resultsUrlstringDirect link to fetch this search's results

Summary Object

Aggregated counts across all searches in the group:

FieldTypeDescription
completedintegerNumber of successfully completed searches
processingintegerNumber of searches still running or initiated
failedintegerNumber of searches that failed

Common Usage Patterns

1. Poll Until All Searches Complete

async function waitForGroupCompletion(searchGroupId, apiKey) {
  const maxAttempts = 30;
  const pollInterval = 2000; // 2 seconds

  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `/v1/public/searches/groups/${searchGroupId}`,
      { headers: { 'X-API-Key': apiKey } }
    );

    const data = await response.json();

    console.log(`Group status: ${data.groupStatus}`);
    console.log(`Progress: ${data.summary.completed}/${data.totalSearches} completed`);

    // Check if done
    if (data.groupStatus === 'completed' || data.groupStatus === 'partial') {
      return data;
    }

    // Wait before next poll
    await new Promise(resolve => setTimeout(resolve, pollInterval));
  }

  throw new Error('Timeout waiting for search group completion');
}

// Usage
const group = await waitForGroupCompletion('group-uuid', 'your-api-key');
console.log('All searches done!');

2. Fetch Results from Completed Searches

async function fetchAllGroupResults(searchGroupId, apiKey) {
  // Get group status
  const groupResponse = await fetch(
    `/v1/public/searches/groups/${searchGroupId}`,
    { headers: { 'X-API-Key': apiKey } }
  );
  const group = await groupResponse.json();

  // Fetch results from all completed searches
  const completedSearches = group.searches.filter(
    s => s.status === 'completed'
  );

  const results = await Promise.all(
    completedSearches.map(async (search) => {
      const res = await fetch(search.resultsUrl, {
        headers: { 'X-API-Key': apiKey }
      });
      return {
        searchId: search.searchId,
        searchType: search.searchType,
        processingTimeMs: search.processingTimeMs,
        data: await res.json()
      };
    })
  );

  return results;
}

// Usage
const allResults = await fetchAllGroupResults('group-uuid', 'your-api-key');
allResults.forEach(r => {
  console.log(`${r.searchType}: ${r.data.totalResults} results in ${r.processingTimeMs}ms`);
});

3. Handle Partial Completion (Some Failures)

async function handleGroupResults(searchGroupId, apiKey) {
  const response = await fetch(
    `/v1/public/searches/groups/${searchGroupId}`,
    { headers: { 'X-API-Key': apiKey } }
  );
  const group = await response.json();

  if (group.groupStatus === 'partial') {
    console.warn('Some searches failed:');

    const failed = group.searches.filter(s => s.status === 'failed');
    failed.forEach(s => {
      console.error(`${s.searchType}: ${s.error}`);
    });
  }

  // Get results from successful searches
  const successful = group.searches.filter(s => s.status === 'completed');
  console.log(`${successful.length} searches succeeded`);

  return successful;
}

4. Compare Processing Times

async function comparePerformance(searchGroupId, apiKey) {
  const response = await fetch(
    `/v1/public/searches/groups/${searchGroupId}`,
    { headers: { 'X-API-Key': apiKey } }
  );
  const group = await response.json();

  // Sort by processing time
  const performance = group.searches
    .filter(s => s.status === 'completed')
    .map(s => ({
      type: s.searchType,
      time: s.processingTimeMs,
      results: s.resultsCount
    }))
    .sort((a, b) => a.time - b.time);

  console.table(performance);

  // Find fastest
  const fastest = performance[0];
  console.log(`Fastest: ${fastest.type} (${fastest.time}ms)`);
}

5. Monitor Long-Running Searches

async function monitorProgress(searchGroupId, apiKey) {
  const response = await fetch(
    `/v1/public/searches/groups/${searchGroupId}`,
    { headers: { 'X-API-Key': apiKey } }
  );
  const group = await response.json();

  // Show progress for each search
  group.searches.forEach(search => {
    const elapsed = search.completedAt
      ? new Date(search.completedAt) - new Date(search.createdAt)
      : Date.now() - new Date(search.createdAt);

    console.log(`${search.searchType}: ${search.status} (${elapsed}ms elapsed)`);
  });

  // Calculate estimated remaining time
  const processing = group.searches.filter(
    s => s.status === 'processing' || s.status === 'initiated'
  );

  if (processing.length > 0) {
    console.log(`${processing.length} searches still running...`);
  }
}

Use Cases

Parallel Search Execution

Launch multiple searches with the same searchGroupId to track them together:

const groupId = crypto.randomUUID();

// Launch 3 searches in parallel
await Promise.all([
  fetch('/v1/public/searches/dense', {
    method: 'POST',
    body: JSON.stringify({ query: 'software engineer', searchGroupId: groupId })
  }),
  fetch('/v1/public/searches/sparse', {
    method: 'POST',
    body: JSON.stringify({ query: 'software engineer', searchGroupId: groupId })
  }),
  fetch('/v1/public/searches/hybrid', {
    method: 'POST',
    body: JSON.stringify({ query: 'software engineer', searchGroupId: groupId })
  })
]);

// Monitor all 3 at once
const group = await fetch(`/v1/public/searches/groups/${groupId}`);

Algorithm Comparison

Compare different search algorithms on the same query:

// After all searches complete
const group = await fetchGroupStatus(groupId);

group.searches.forEach(search => {
  console.log(`${search.searchType}:`);
  console.log(`  - Results: ${search.resultsCount}`);
  console.log(`  - Time: ${search.processingTimeMs}ms`);
});

Error Handling

404 - Group Not Found

{
  "error": "Search group not found",
  "searchGroupId": "uuid"
}

Possible reasons:

  • Invalid searchGroupId
  • Group doesn't belong to your company
  • No searches have been created with this group ID yet

500 - Server Error

{
  "error": "Failed to get search group",
  "message": "Error details"
}

Action: Retry request or contact support


Performance Notes

  • Response size: ~0.5-1KB per search in group
  • Typical groups: 2-4 searches
  • No rate limits: Safe to poll frequently
  • Data retention: Group data persists indefinitely

  • GET /v1/public/searches/{searchId} - Get status of a single search
  • GET /v1/public/searches/{searchId}/results - Fetch results for a completed search
  • GET /v1/public/searches/groups/{searchGroupId}/results - Compare results across all searches in group (if available)

Quick Reference

// 1. Create searches with same groupId
const groupId = crypto.randomUUID();
await createSearchWithGroup(query, 'dense', groupId);
await createSearchWithGroup(query, 'sparse', groupId);

// 2. Check group status
const group = await fetch(`/v1/public/searches/groups/${groupId}`);

// 3. Wait for completion
while (group.groupStatus === 'processing') {
  await sleep(2000);
  group = await fetch(`/v1/public/searches/groups/${groupId}`);
}

// 4. Fetch all results
const results = await Promise.all(
  group.searches
    .filter(s => s.status === 'completed')
    .map(s => fetch(s.resultsUrl))
);
GET
/v1/public/searches/groups/{searchGroupId}
X-API-Key<token>

API key for public API access. Get yours at https://app.floreal.ai?tab=api

In: header

Path Parameters

searchGroupIdstring
Formatuuid

Response Body

curl -X GET "https://api.floreal.ai/v1/public/searches/groups/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{
  "searchGroupId": "6057d3c7-e3bb-4624-80c0-432d9633004b",
  "groupStatus": "initiated",
  "query": "string",
  "totalSearches": 0,
  "searches": [
    {
      "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
      "searchType": "dense",
      "status": "initiated",
      "resultsCount": 0,
      "processingTimeMs": 0,
      "error": "string",
      "createdAt": "2019-08-24T14:15:22Z",
      "completedAt": "2019-08-24T14:15:22Z",
      "statusUrl": "string",
      "resultsUrl": "string"
    }
  ],
  "summary": {
    "completed": 0,
    "processing": 0,
    "failed": 0
  }
}
{
  "error": "string",
  "message": "string"
}
{
  "error": "string"
}
{
  "error": "string",
  "message": "string"
}