Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ivory.finance/llms.txt

Use this file to discover all available pages before exploring further.

Discover Tables on Filing

Scans a corporate disclosure to find all tables without extracting data. Use this to show users which tables are available so they can choose what to extract.

Request

s3_url
string
required
URL to the corporate disclosure filing HTML (must be publicly accessible)
table_index
integer
Ignored for discovery. Include any value (e.g., 0)
export_format
string
Ignored for discovery. Include any value (e.g., ‘csv’)

Response

table_count
integer
Total number of tables found on the page
tables
array
Array of table metadata objects

Usage Example

1. Basic Discovery

const response = await fetch('https://api.ivory.finance/v1/tools/extract/discover', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    s3_url: 'https://www.sec.gov/Archives/edgar/.../form-10k.htm',
    table_index: 0,
    export_format: 'json'
  })
});

const data = await response.json();
console.log(`Found ${data.table_count} tables`);

data.tables.forEach(table => {
  console.log(`Table ${table.index}: ${table.rows} rows × ${table.columns} cols`);
  console.log(`Preview: ${table.preview}`);
});

2. Build Table Selector

Display a dropdown for users to choose which table to extract:
async function showTableSelector(filingUrl) {
  const response = await fetch('https://api.ivory.finance/v1/tools/extract/discover', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      s3_url: filingUrl,
      table_index: 0,
      export_format: 'json'
    })
  });

  const data = await response.json();

  const select = document.createElement('select');

  data.tables.forEach(table => {
    const option = document.createElement('option');
    option.value = table.index;
    option.textContent = `Table ${table.index + 1} (${table.rows} rows, ${table.columns} cols) - ${table.preview}`;
    select.appendChild(option);
  });

  const container = document.getElementById('table-selector');
  container.innerHTML = '';
  container.appendChild(select);

  return select;
}

// Usage
const tableDropdown = await showTableSelector(filingUrl);
tableDropdown.addEventListener('change', (e) => {
  const selectedTable = e.target.value;
  // Trigger extraction of selected table
});

3. Filter Tables by Size

Find only tables with minimum size:
async function getLargeTables(filingUrl, minRows = 5, minCols = 3) {
  const response = await fetch('https://api.ivory.finance/v1/tools/extract/discover', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      s3_url: filingUrl,
      table_index: 0,
      export_format: 'json'
    })
  });

  const data = await response.json();

  return data.tables.filter(table =>
    table.rows >= minRows && table.columns >= minCols
  );
}

// Get tables that are likely to be meaningful financial data
const largeTables = await getLargeTables(filingUrl, minRows: 3, minCols: 2);

4. Smart Table Detection

Identify financial statement tables by preview content:
async function findFinancialStatements(filingUrl) {
  const response = await fetch('https://api.ivory.finance/v1/tools/extract/discover', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      s3_url: filingUrl,
      table_index: 0,
      export_format: 'json'
    })
  });

  const data = await response.json();

  const patterns = {
    income: /revenue|income|earnings|expenses/i,
    balance: /balance.*sheet|assets|liabilities|equity/i,
    cashflow: /cash.*flow|operating|investing|financing/i
  };

  return data.tables.map(table => {
    let type = 'other';
    for (const [key, pattern] of Object.entries(patterns)) {
      if (pattern.test(table.preview)) {
        type = key;
        break;
      }
    }
    return { ...table, type };
  });
}

// Find and categorize statements
const statements = await findFinancialStatements(filingUrl);
statements.forEach(stmt => {
  console.log(`${stmt.type}: Table ${stmt.index}`);
});

Response Format

{
  "table_count": 5,
  "tables": [
    {
      "index": 0,
      "rows": 12,
      "columns": 5,
      "preview": "Consolidated Statements of Income (In thousands)"
    },
    {
      "index": 1,
      "rows": 8,
      "columns": 4,
      "preview": "Earnings Per Share 2023 2022 2021"
    },
    {
      "index": 2,
      "rows": 15,
      "columns": 6,
      "preview": "Consolidated Balance Sheet Assets Current assets"
    },
    {
      "index": 3,
      "rows": 3,
      "columns": 3,
      "preview": "Dividends Per Share"
    },
    {
      "index": 4,
      "rows": 1,
      "columns": 1,
      "preview": "  "
    }
  ]
}

Typical Response Times

  • Simple filings (few tables): < 500ms
  • Large filings (50+ tables): 1-3 seconds
  • Very large filings (100+ tables): 3-5 seconds

After Discovery

Once you’ve discovered tables, use the table index with Extract Table to get the actual data:
// 1. Discover tables
const discovered = await discoverTables(filingUrl);

// 2. User selects a table
const selectedIndex = 0;

// 3. Extract the selected table
const extracted = await extractTable(filingUrl, selectedIndex, 'xlsx');

Common Patterns

Pattern 1: Auto-Extract Income Statement

async function extractIncomeStatement(filingUrl) {
  const discovered = await discoverTables(filingUrl);

  // Find table with "Income" or "Statement" in preview
  const incomeTable = discovered.tables.find(t =>
    /income|statement of income/i.test(t.preview)
  );

  if (!incomeTable) {
    throw new Error('Income statement not found');
  }

  return await extractTable(
    filingUrl,
    incomeTable.index,
    'xlsx'
  );
}

Pattern 2: Extract All Financial Statements

async function extractAllStatements(filingUrl) {
  const discovered = await discoverTables(filingUrl);

  const financial = discovered.tables.filter(t => {
    const preview = t.preview.toLowerCase();
    return (
      preview.includes('income') ||
      preview.includes('balance') ||
      preview.includes('cash flow') ||
      preview.includes('equity')
    ) && t.rows > 3;
  });

  return await Promise.all(
    financial.map(t =>
      extractTable(filingUrl, t.index, 'json')
    )
  );
}

Errors

503 - Fetch Failed
{
  "detail": {
    "error": "fetch_failed",
    "message": "Failed to fetch the filing",
    "details": "Connection timeout"
  }
}
500 - Processing Error
{
  "detail": {
    "error": "discovery_failed",
    "message": "Failed to discover tables",
    "details": "HTML parsing error"
  }
}