# API submits and result checks, 2x faster

> Submitting a document now takes 314 ms at the median, down from 670 ms, and result checks are twice as fast. SDK 0.9.1 picks up finished results sooner.

- Canonical: https://www.datalab.to/blog/faster-api-responses
- Published: 2026-11-06
- Authors: Datalab Team

This week the Datalab API got faster at the parts that are not document processing: accepting your upload, and answering when you check for a result. At the median, submitting a document to `/api/v1/marker` takes 314 ms, down from 670 ms last week. A result check takes 62 ms, down from 128 ms. The slowest 1% of result checks dropped from 869 ms to 283 ms.

We also released version 0.9.1 of the Python SDK. It checks for your result every 0.3 seconds for the first 8 seconds, so it picks up a finished page sooner.

You don't need to change anything to get the faster API. To get the faster polling, upgrade the SDK.

## What changed

Every API call to Datalab has three parts:

1. **Submit.** You upload a file and get back a request ID.
2. **Process.** We parse or extract the document.
3. **Check for the result.** You poll the request's check URL until the result is ready.

This post covers parts 1 and 3. Here are the server times from our production request traces, comparing Oct 29–31 with Nov 3–6:

<img src="/images/blog/faster-api-responses/api-latency.svg" alt="API response times, Oct 29–31 vs Nov 3–6. Submits and result checks are about twice as fast at the median, and the slowest result checks are about three times faster." style="display:block;width:100%;max-width:760px;margin-inline:auto" />

| Request                            | Percentile | Oct 29–31 | Nov 3–6 |
| ---------------------------------- | ---------- | --------- | ------- |
| `POST /api/v1/marker`              | p50        | 670 ms    | 314 ms  |
| `POST /api/v1/marker`              | p90        | 1,133 ms  | 693 ms  |
| `POST /api/v1/extract`             | p50        | 708 ms    | 350 ms  |
| `POST /api/v1/extract`             | p90        | 1,586 ms  | 828 ms  |
| `POST /api/v1/convert`             | p50        | 598 ms    | 362 ms  |
| `GET /api/v1/marker/{request_id}`  | p50        | 128 ms    | 62 ms   |
| `GET /api/v1/marker/{request_id}`  | p99        | 869 ms    | 283 ms  |
| `GET /api/v1/convert/{request_id}` | p99        | 891 ms    | 315 ms  |
| `GET /api/v1/extract/{request_id}` | p90        | 344 ms    | 221 ms  |

These are times measured on our servers. Your upload time over your own network comes on top of them, so a large file on a slow connection still takes longer to submit.

We also measured the whole wait outside processing for single-page jobs, from the moment we accept the request to the moment its result is ready, minus the processing time. That fell from 1.30 s to 1.19 s at the median. Processing time per page did not change this week. We have covered model speed separately, most recently in the [Chandra 2.6 post](/blog/chandra-2-6).

## Why it matters

A single page in fast mode is ready in a few seconds, so a second of overhead is a large share of the wait your user sees. The gains add up in three places:

- **Submits.** Each submit returns about 350 ms sooner. If one worker submits documents one after another, it saves about an hour per 10,000 documents.
- **Result checks.** A check returns about twice as fast at the median, and the slow ones stopped being slow. If your client polls hundreds of requests at once, it spends less time waiting on the API.
- **Polling interval.** If you poll once a second, a finished result waits 0.5 s on average before your next check sees it. At 0.3 s, it waits 0.15 s on average.

## How to use it

### Python SDK

Upgrade to 0.9.1:

```bash
pip install -U datalab-python-sdk
```

You don't need to change your code. The client checks every 0.3 seconds for the first 8 seconds of a request, then every `poll_interval` seconds (1 second by default):

```python
from datalab_sdk import DatalabClient

client = DatalabClient()  # reads DATALAB_API_KEY

result = client.convert("invoice.pdf")
print(result.markdown)
```

The time budget is the same as before: the waits between checks add up to `max_polls * poll_interval` seconds. If you set `poll_interval` above 1 second, for example for long batch jobs, the client skips the fast checks:

```python
# A 500-page report: check every 5 seconds from the start
result = client.convert("annual-report.pdf", poll_interval=5, max_polls=240)
```

We raised the result-check rate limit to three times its old value, so a team at its request limit can poll every 0.3 seconds without getting 429 responses.

### Your own HTTP client

If you call the API directly, start with a short interval and increase it slowly:

```python
import os
import time

import requests

headers = {"X-API-Key": os.environ["DATALAB_API_KEY"]}
with requests.Session() as session:
    with open("invoice.pdf", "rb") as file:
        response = session.post(
            "https://www.datalab.to/api/v1/convert",
            files={"file": ("invoice.pdf", file, "application/pdf")},
            data={"output_format": "markdown"},
            headers=headers,
            timeout=60,
        )
    response.raise_for_status()
    check_url = response.json()["request_check_url"]

    delay = 0.3  # check often at first: most single pages finish in seconds
    for _ in range(300):
        response = session.get(check_url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()
        if result.get("success") is False or result.get("status") == "failed":
            raise RuntimeError(result.get("error") or "Conversion failed")
        if result["status"] == "complete":
            if result.get("result_url"):
                # Large results come back as a signed URL: download it without the API key header.
                result = session.get(result["result_url"], timeout=60).json()
            print(result["markdown"])
            break
        time.sleep(delay)
        delay = min(delay * 1.15, 1)  # back off to one check per second
```

The [quickstart](https://documentation.datalab.to/docs/welcome/quickstart) shows the same request with cURL and the SDK.

## Example use cases

- **Upload in your app.** Your user drops in a scanned receipt and waits for the fields. With a faster submit, faster checks, and the 0.3 s polling in SDK 0.9.1, most of the wait is the parsing itself.
- **Agents that read documents.** An agent that calls `/extract` once per page in a loop pays the submit and check time on every page. The median submit for `/extract` dropped from 708 ms to 350 ms.
- **High-volume single-page jobs.** Pipelines that send many one-page images, such as ID cards, shipping labels or forms, spend a large share of their time in submits and checks. They get the largest relative gain.

## Try it

- [Sign up](https://www.datalab.to) and get an API key. New accounts get free credits to try the API.
- Upgrade the SDK with `pip install -U datalab-python-sdk`.
- Read the [API docs](https://documentation.datalab.to/docs/welcome/api).

If you see slow responses from the API, email [support@datalab.to](mailto:support@datalab.to) with the request ID, and we'll look at the trace.
