> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runpulse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tables

> Get every table in a parse as HTML, JSON or Markdown, with tables that continue across pages joined into one.

Tables returns every table in a completed parse, and joins a table that continues across pages back into one. Use it when rows and columns are the output you need. To pull a few values out of tables, use [Extract](https://docs.runpulse.com/v2/extract.md) instead.

Tables reads the parse by its `parse_id`, so the document isn't read again:

```mermaid theme={null}
%%{init: {"themeVariables": {"fontSize": "14px"}, "flowchart": {"nodeSpacing": 24, "rankSpacing": 32, "padding": 8}}}%%
flowchart LR
    parse["POST /parse"] -->|parse_id| tables["POST /tables"]
    tables -->|tables_id| result["GET .../result"]
```

## Get a parse's tables

This example parses the sample bank statement, then reads its tables as JSON and Markdown:

```python Python theme={null}
import os
from pulse import Pulse

client = Pulse(api_key=os.environ["PULSE_API_KEY"])

parse = client.parse.run(
    file_url="https://platform.runpulse.com/api/examples/637e5678-30b1-45fa-acc4-877f2d636419/pdf",
    config={"model": "ultra-2"},
)
job = client.tables.run(parse_id=parse.parse_id, config={"format": ["json", "md"]})

for table in client.tables.get_result(job.tables_id).tables:
    print(table.source_element_ids)
    print(table.content.md)
```

```typescript TypeScript theme={null}
import { PulseClient } from "@pulse-software/sdk";

const client = new PulseClient({ apiKey: process.env.PULSE_API_KEY! });

const { parseId } = await client.parse.run({
  fileUrl: "https://platform.runpulse.com/api/examples/637e5678-30b1-45fa-acc4-877f2d636419/pdf",
  config: { model: "ultra-2" },
});
const { tablesId } = await client.tables.run({ parseId, config: { format: ["json", "md"] } });

const { tables } = await client.tables.getResult({ tablesId });
for (const table of tables) {
  console.log(table.sourceElementIds);
  console.log(table.content.md);
}
```

For a long document, send `async: true` and poll the job: see [Jobs and results](https://docs.runpulse.com/v2/jobs.md). Tables can't read an expired or deleted parse.

> [!NOTE]
>
> Tables must be turned on for your organization. Until it is, `POST /tables` returns `404`, as a route that doesn't exist, and a [pipeline](https://docs.runpulse.com/v2/pipelines.md) with a Tables step returns `400`. To turn it on, contact [support](https://docs.runpulse.com/v2/support.md).

Tables works from the parse's tables as they are. To fix misread cells first, parse with the [`tables` refine pass](https://docs.runpulse.com/v2/parse#correct-tables-text-and-layout).

***

## Choose formats and pages

`config.format` picks the formats each table comes back in, `["html"]` by default. Send `"all"` for all three.

| Format | What you get |
| - | - |
| `html` | HTML with `<th>` header cells and `rowspan` and `colspan` kept, to show the table's structure. |
| `json` | `headers`, one per column, and `cells`, one list per row, to load into a dataframe or a database. |
| `md` | A GitHub-flavored Markdown table, for prompts and quick review. |

In the Python SDK, `json` is `content.json_`.

`config.page_range` takes tables from some pages only, such as `"3-7"`, numbered as the parse numbers them. If you leave it out, Tables reads every page of the parse. A table joins only with tables on the selected pages. A range past the parse's last page is refused with a `400`.

***

## Read the result

`GET /tables/{tables_id}/result` (`client.tables.get_result`) returns the tables in reading order, one entry per joined table. Here, one table continues from page 1 to page 2:

```json theme={null}
{
  "tables_id": "tables-8d2f4c71-5a9e-4b3d-a0c6-1e7f9b2d4a58",
  "tables": [
    {
      "source_element_ids": ["Table-6", "Table-14"],
      "content": {
        "json": {
          "headers": ["Date", "Description", "Amount"],
          "cells": [
            ["03/02", "Card payment", "-42.10"],
            ["03/04", "Payroll deposit", "2,150.00"]
          ]
        },
        "md": "| Date | Description | Amount |\n| --- | --- | --- |\n| 03/02 | Card payment | -42.10 |\n| 03/04 | Payroll deposit | 2,150.00 |"
      }
    }
  ],
  "usage": {
    "request": { "pages_processed": 2, "credits_used": 0.5 }
  },
  "history": {
    "file_name": "statement.pdf",
    "previous_step": "parse-3f6c1a2e-8d4b-4f7a-9c2e-5b1d0e7a4c93"
  }
}
```

`source_element_ids` names the parse's `Table` elements the table was built from, first part first. Look them up in the parse's [`elements`](https://docs.runpulse.com/v2/elements) to find each part's page and box:

```mermaid theme={null}
%%{init: {"themeVariables": {"fontSize": "14px"}, "flowchart": {"nodeSpacing": 24, "rankSpacing": 32, "padding": 8}}}%%
flowchart LR
    a["Table-6, page 1"] --> t["One table"]
    b["Table-14, page 2"] --> t
    t --> ids["source_element_ids:<br/>Table-6, Table-14"]
```

Every cell is text, even when it holds a number, so convert values yourself.

## Check merge warnings

If a pass that finds or checks joins across pages fails, the job still completes and `warnings` names what it did without:

| Warning | What happened |
| - | - |
| `TABLE_ANALYSIS_SKIPPED` | The AI analysis failed, so tables were joined by layout rules only. |
| `MERGE_NOT_VERIFIED` | The AI check failed, so the joins were kept unchecked. |
| `MERGE_FALLBACK` | The layout couldn't be read, so tables were joined by position only. |

If you see one, check the joins against the source before you rely on them.

***

## Pricing

Tables costs 0.5 credits per table returned, and a table joined from several pages counts as one ([Pricing](https://docs.runpulse.com/v2/pricing.md)).

## Next steps

> [card] [Extract](https://docs.runpulse.com/v2/extract.md)
>
> Pull a few values out of a parse.

> [card] [Pipelines](https://docs.runpulse.com/v2/pipelines.md)
>
> Parse and read tables in one call.

> [card] [Tables API reference](https://docs.runpulse.com/api-reference/v2/tables/run-tables.md)
>
> Every option, field and limit.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.