# Authentication URL: https://docbeast.com/docs/authentication Send your key in either header: ```bash -H "Authorization: Bearer dbk_live_..." -H "x-api-key: dbk_live_..." ``` ## Kinds of key | Key | Starts with | Where it comes from | What it spends | | --- | --- | --- | --- | | Account key | `dbk_live_` | The [dashboard](https://docbeast.com/dash) | The pages on your [plan](https://docbeast.com/docs/plans) | | Credit key | `dbk_pack_` | [Pay per use](https://docbeast.com/docs/pay-per-use) | The pages it was bought with | A new account's first key is shown once on the dashboard, and you can create more there. Copy a key when you create it. Only a hash is stored, so it can't be shown again. If a key leaks, revoke it from the dashboard and make a new one. ## Without a key `POST /v1/convert` works without a key. It reads the first page of a file, 3 times a day. There's also a limit on free conversions across all users each day, so they can run out sooner. When they've run out, you get `402` with a payment challenge if [pay per use](https://docbeast.com/docs/pay-per-use) is on, and otherwise `429 free_limit_reached`. See [Errors](https://docbeast.com/docs/errors). ## What needs a key | Endpoint | Key | | --- | --- | | `POST /v1/convert` | Optional | | `GET /v1/jobs/{id}` | Not needed | | `GET /v1/jobs/{id}/result.{format}` | Not needed | | `GET /v1/usage` | Required | Reading a job needs only its id, so treat ids as private. Each one is a long random string that can't be guessed. ## Check your usage ```bash curl https://api.docbeast.com/v1/usage -H "Authorization: Bearer dbk_live_..." ``` With an account key: ```json { "kind": "plan", "plan": "starter", "period": "2026-11-01T00:00:00Z", "pages_used": 42, "pages_included": 100, "pages_remaining": 58 } ``` With a credit key: ```json { "kind": "credits", "pages_remaining": 25 } ``` `period` is your subscription's start on a paid plan, or the month (`2026-11`) on the Free plan. ## OAuth AI clients that connect to the [MCP server](https://docbeast.com/docs/mcp) can sign in with OAuth, so you don't have to paste a key. Those access tokens only work on the MCP server, not on the REST API. # Convert a file URL: https://docbeast.com/docs/convert ```bash curl -X POST "https://api.docbeast.com/v1/convert?wait=25&filename=list.pdf" \ -H "Authorization: Bearer dbk_live_..." \ --data-binary @list.pdf ``` ## The file Send the file as the request body, or in a form field named `file`: ```bash curl -X POST "https://api.docbeast.com/v1/convert?wait=25" \ -H "Authorization: Bearer dbk_live_..." \ -F "file=@list.pdf" ``` PDF, PNG, JPEG, WebP, TIFF and HEIC files work, up to 25 MB. docbeast works out the type from the file's contents, so its name and `Content-Type` don't matter. The file is checked before anything else, so an upload that's rejected doesn't use up any pages or free conversions. ## Query parameters | Parameter | Default | What it does | | --- | --- | --- | | `mode` | `table` | `table` keeps rows and columns, and leaves out text around a table. `text` reads the page as plain text. | | `wait` | `0` | Seconds to hold the request open for the result, up to 25. | | `filename` | None | A name for the file, used to name the downloads. | You can also set the name with an `x-filename` header, and a form upload uses the name of the uploaded file. Paths are dropped from it and it's cut to 120 characters. ## Responses The body is a [job](https://docbeast.com/docs/jobs) in all of these. | Status | Meaning | | --- | --- | | `200` | Finished within `wait`. `downloads` has the links. | | `202` | Queued or still running. Check it with `GET /v1/jobs/{id}`. | | `422` | The job failed within `wait`. Its `error` says why. | Other statuses are errors, listed under [Errors](https://docbeast.com/docs/errors). ## Long files Each kind of access has a limit on pages per file, and only that many are converted, from the start of the file. The rest are reported in `pages_skipped`, so a 60-page PDF on a plan with a 50-page limit comes back with `pages_converted: 50` and `pages_skipped: 10`. The limits are under [Plans and limits](https://docbeast.com/docs/plans). An account that has fewer pages left this period than a file needs gets as many as it has left. A file can't start at all if there are no pages left. ## What you're charged Only pages that were read successfully count. A failed job costs nothing, and neither does a page that couldn't be read. # Errors URL: https://docbeast.com/docs/errors Errors are JSON with a stable `code` and a message you can show to people. Use the `code` in your own logic, because messages can change. ```json { "error": { "code": "unsupported_file", "message": "Send a PDF, PNG, JPEG, WebP, TIFF or HEIC." } } ``` A job that was accepted and then failed is reported on the job, not as an error like this. See [When a job fails](https://docbeast.com/docs/jobs#when-a-job-fails). | Status | Code | When | | --- | --- | --- | | `400` | `bad_mode` | `mode` isn't `table` or `text`. | | `400` | `missing_file` | The request had no file, or no form field named `file`. | | `401` | `unauthorized` | The key is invalid or has been revoked. On `GET /v1/usage`, it's also missing. | | `402` | `payment_required` | Today's free conversions are used. See [Pay per use](https://docbeast.com/docs/pay-per-use). | | `402` | `payment_error` | A payment couldn't be processed. | | `402` | `credits_used` | The credit key has no pages left. Send the request without a key to buy more. | | `404` | `not_found` | There's no such job, it has expired, or the path doesn't exist. | | `409` | `not_ready` | A result was requested before the job finished, or for a failed job. | | `410` | `expired` | The result has been deleted. | | `413` | `file_too_large` | The file is over 25 MB. | | `415` | `unsupported_file` | The file isn't a PDF, PNG, JPEG, WebP, TIFF or HEIC. | | `429` | `quota_exceeded` | The account has used its pages for the period. | | `429` | `free_limit_reached` | Today's free conversions are used and pay per use isn't on. | | `500` | `internal_error` | Something broke on our side. Try again in a minute. | Errors from the [MCP server](https://docbeast.com/docs/mcp) are listed there. # Quickstart URL: https://docbeast.com/docs docbeast reads scanned PDFs and photos of documents and gives you their tables as rows. The base URL for every request is `https://api.docbeast.com`. ## 1. Convert a file You can try the API without an account. The first page of a file is free, 3 times a day. ```bash curl -X POST "https://api.docbeast.com/v1/convert?wait=25&filename=list.pdf" \ --data-binary @list.pdf ``` `wait=25` holds the request open for up to 25 seconds, so a short file can finish in the same response. See [Convert a file](https://docbeast.com/docs/convert) for the other options. ## 2. Read the response This is an example. Your id and times will differ. ```json { "id": "job_cbff845fa8cb4e0a9f3d26b14c7e5a10", "status": "done", "filename": "list.pdf", "page_count": 1, "pages_converted": 1, "pages_skipped": 0, "error": null, "created_at": "2026-11-09T10:44:51Z", "expires_at": "...", "downloads": { "json": "https://api.docbeast.com/v1/jobs/job_cbff845fa8cb4e0a9f3d26b14c7e5a10/result.json", "csv": "https://api.docbeast.com/v1/jobs/job_cbff845fa8cb4e0a9f3d26b14c7e5a10/result.csv", "xlsx": "https://api.docbeast.com/v1/jobs/job_cbff845fa8cb4e0a9f3d26b14c7e5a10/result.xlsx" } } ``` If `status` is still `queued` or `running`, the response is a `202`. Check again with `GET /v1/jobs/{id}`. See [Jobs](https://docbeast.com/docs/jobs). ## 3. Download the result The links in `downloads` need no key. Files are deleted automatically after a short time, so save what you need. ```bash curl -o list.xlsx "https://api.docbeast.com/v1/jobs/job_cbff845fa8cb4e0a9f3d26b14c7e5a10/result.xlsx" ``` ## 4. Get an API key Longer files need an account. [Sign in](https://docbeast.com/login) with your email address and we send you a sign-in link. A new account gets 10 free pages a month, and its first key is waiting on the [dashboard](https://docbeast.com/dash). Then send the key with each request: ```bash curl -X POST "https://api.docbeast.com/v1/convert?wait=25&filename=list.pdf" \ -H "Authorization: Bearer dbk_live_..." \ --data-binary @list.pdf ``` ## Next steps - [Authentication](https://docbeast.com/docs/authentication): keys, and what works without one. - [Results and formats](https://docbeast.com/docs/results): the JSON shape, and how Excel and CSV files are built. - [MCP server](https://docbeast.com/docs/mcp): use docbeast from an AI agent. - [Plans and limits](https://docbeast.com/docs/plans): pages, file sizes and prices. # Jobs URL: https://docbeast.com/docs/jobs Every conversion is a job. `POST /v1/convert` returns one, and you can read it any time: ```bash curl https://api.docbeast.com/v1/jobs/job_cbff845fa8cb4e0a9f3d26b14c7e5a10 ``` ```json { "id": "job_cbff845fa8cb4e0a9f3d26b14c7e5a10", "status": "running", "filename": "list.pdf", "page_count": null, "pages_converted": 0, "pages_skipped": 0, "error": null, "created_at": "2026-11-09T10:44:51Z", "expires_at": "...", "downloads": null } ``` ## Fields | Field | Meaning | | --- | --- | | `id` | The job's id. It's all that's needed to read the result, so keep it private. | | `status` | `queued`, `running`, `done` or `failed`. | | `filename` | The name you gave the file, or `null`. | | `page_count` | Pages in the document, once known. | | `pages_converted` | Pages read successfully. Only these count against your account. | | `pages_skipped` | Pages left out because of a [page limit](https://docbeast.com/docs/plans). | | `error` | `{ "code", "message" }` when `status` is `failed`, otherwise `null`. | | `created_at` | When the job started, in UTC. | | `expires_at` | When the job and its files are deleted. | | `downloads` | Links to `json`, `csv` and `xlsx` files when `status` is `done`, otherwise `null`. | ## Waiting for a result A job can wait in the queue while other files are ahead of it. For a job that isn't finished after `wait`, poll `GET /v1/jobs/{id}` every few seconds until `status` is `done` or `failed`. A job that hits a temporary problem is retried automatically, and can go back to `queued` while it waits. ## When a job fails A failed job is still a `200` from `GET /v1/jobs/{id}`, with `status` set to `failed`. If you were waiting on `POST /v1/convert` when it failed, that response is a `422`. | Error code | Message | | --- | --- | | `unreadable_file` | The file couldn't be opened. Check that it isn't password-protected or damaged. | | `quota_exceeded` | No pages left on this account or key. | | `conversion_failed` | The document couldn't be converted. You weren't charged. Try again in a few minutes. | | `upload_missing` | The uploaded file is no longer available. | A failed job costs nothing, and a free conversion that failed is given back. ## Expiry Files and jobs are deleted automatically after a short time. `expires_at` tells you when. After that, the job answers `404`. # MCP server URL: https://docbeast.com/docs/mcp docbeast has a remote [Model Context Protocol](https://modelcontextprotocol.io) server, so AI clients can convert documents. The server URL is: ```text https://mcp.docbeast.com/mcp ``` ## Connect **Without signing in**, a client can use the free conversions: the first page of a file, 3 times a day. There's nothing to set up. **With OAuth**, add the URL as a custom connector in your client. It sends you to docbeast to sign in with your email link, and you choose **Allow**. You never paste a key. To disconnect a client later, use **Connected apps** on the [dashboard](https://docbeast.com/dash). **With an API key**, for clients that let you set headers: ```json { "mcpServers": { "docbeast": { "url": "https://mcp.docbeast.com/mcp", "headers": { "Authorization": "Bearer dbk_live_..." } } } } ``` Account keys and credit keys both work. See [Authentication](https://docbeast.com/docs/authentication). ## Tools | Tool | What it does | Counts pages | | --- | --- | --- | | `convert_document` | Reads a PDF or image and returns its tables and download links. | Yes | | `get_conversion` | Reads a conversion's status and, when finished, its tables and download links. | No | | `get_usage` | Shows the pages used and remaining. Needs a sign-in or key. | No | ### convert_document | Argument | Meaning | | --- | --- | | `url` | An `https` link to the document. Give this or `base64`, not both. | | `base64` | The document's bytes, base64-encoded. | | `filename` | A name for the file, used to name the downloads. | | `mode` | `table` (default) keeps rows and columns. `text` reads the page as plain text. | The tool waits up to 45 seconds. If the conversion is still `queued` or `running` after that, it returns the job's id and status, and the client can follow up with `get_conversion`. The conversion keeps going either way. The result is the same [job](https://docbeast.com/docs/jobs) as the REST API returns, with the tables and text added as `pages`. Only the first 200 rows are included, and the download links have everything. ## Limits MCP uses the same [plans and limits](https://docbeast.com/docs/plans) as the API, and pages are counted the same way. Files can be up to 25 MB. Some problems are returned as a tool result with `isError` and a code: | Code | Meaning | | --- | --- | | `bad_input` | Give exactly one of `url` or `base64`. | | `bad_url` | The link isn't valid or isn't `https`. | | `fetch_failed` | Downloading the document failed. | | `bad_base64` | The `base64` value couldn't be decoded. | | `file_too_large` | The document is over 25 MB. | | `unsupported_file` | The file isn't a supported type. | | `limit_reached` | The account or key has no pages left. | | `not_found` | There's no such conversion, or it has expired. | Sign-in problems are HTTP errors instead, so the client can start OAuth. A credential that's invalid, expired or revoked gets a `401` on any message, and a call without a credential gets a `401` once today's free conversions are used. ## Discovery | URL | What it is | | --- | --- | | `https://mcp.docbeast.com/.well-known/mcp.json` | Server name, tools and links, for registries. | | `https://mcp.docbeast.com/.well-known/oauth-protected-resource` | OAuth protected resource metadata. | | `https://docbeast.com/.well-known/oauth-authorization-server` | OAuth authorization server metadata. | # Pay per use URL: https://docbeast.com/docs/pay-per-use An agent without an account can pay for a pack of pages on the spot. There's nothing to sign up for. Payment uses [MPP](https://mpp.dev), a way to pay over HTTP, by card or in USDC on Tempo. A pack costs **$0.50 for 25 pages**. Pay per use is only offered once the free conversions are used, and only when it's turned on. If it isn't, you get `429 free_limit_reached` instead. ## How it works 1. Send `POST /v1/convert` without a key. 2. Once today's free conversions are used, the API answers `402` with a payment challenge in the `WWW-Authenticate` header. 3. Pay the challenge and send the same request again with the payment in the `Authorization` header. 4. The conversion runs, and the response carries the new key. ```bash HTTP/1.1 402 Payment Required WWW-Authenticate: Payment ... { "error": { "code": "payment_required", "message": "..." } } ``` An MPP client library handles steps 2 and 3 for you. ## The key you get back The paid response has these headers: | Header | Meaning | | --- | --- | | `x-docbeast-key` | A credit key, `dbk_pack_...`, for the pages you bought. | | `x-docbeast-credits` | How many pages the pack holds. | Save the key and send it as a normal [API key](https://docbeast.com/docs/authentication). Pages come off it only when they're converted, so a failed job costs nothing. It works on the [MCP server](https://docbeast.com/docs/mcp) too. Each file can be up to 25 pages. To check what's left, call `GET /v1/usage` with the key. When the key runs out, `POST /v1/convert` answers `402 credits_used`. Send the request without a key to buy another pack. # Plans and limits URL: https://docbeast.com/docs/plans | Plan | Price | Pages | Pages per file | | --- | --- | --- | --- | | Free | Free | 10 pages a month | 10 | | Starter | $4.99 a month | 100 pages a month | 50 | | Pro | $19 a month | 1,000 pages a month | 50 | | No account | Free | The first page of a file, 3 times a day | 1 | | Pay per use | $0.50 | 25 pages a pack | 25 | Files can be up to 25 MB on every plan. You're only charged for pages that were converted. ## How pages are counted - A page counts only when it was read successfully. A failed job costs nothing. - An image is one page, and each frame of a multi-page TIFF counts as a page. - A file longer than its limit is converted from the start, and the rest is reported in `pages_skipped`. - `GET /v1/usage` shows what's left. See [Authentication](https://docbeast.com/docs/authentication). Paid plans reset each billing period, and the Free plan resets each calendar month. Unused pages don't carry over. See the [pricing page](https://docbeast.com/pricing) to upgrade. ## Limits for everyone | Limit | Value | | --- | --- | | File size | 25 MB | | File types | PDF, PNG, JPEG, WebP, TIFF, HEIC | | Waiting on a request | Up to 25 seconds with `wait` | Results are deleted automatically after a short time, so download what you need. # Results and formats URL: https://docbeast.com/docs/results A finished job has three downloads. They need no key. ```bash curl -o list.xlsx "https://api.docbeast.com/v1/jobs/job_cbff.../result.xlsx" curl -o list.csv "https://api.docbeast.com/v1/jobs/job_cbff.../result.csv" curl "https://api.docbeast.com/v1/jobs/job_cbff.../result.json" ``` Excel and CSV files are sent as downloads named after your file. If the job isn't finished, these return `409 not_ready`, and once a result has been deleted they return `410 expired`. ## JSON ```json { "id": "job_cbff845fa8cb4e0a9f3d26b14c7e5a10", "filename": "list.pdf", "page_count": 2, "pages": [ { "page": 1, "tables": [{ "rows": [["Part no.", "Pack"], ["00412", "100"]] }], "text": "", "seconds": 4.2, "truncated": false }, { "page": 2, "tables": [], "text": "", "seconds": 0, "truncated": false, "error": "..." } ] } ``` | Field | Meaning | | --- | --- | | `page_count` | Pages in the document. | | `pages[].page` | The page number, starting at 1. | | `pages[].tables` | The tables found, each as `rows`: an array of rows, each an array of cell strings. | | `pages[].text` | Text outside any table. In `text` mode, the page's text. | | `pages[].seconds` | How long the page took to read. | | `pages[].truncated` | `true` means the page hit a length limit and may be incomplete. | | `pages[].error` | Only there when this page couldn't be read. Its `tables` and `text` are empty. | Every cell is a string, so nothing is lost: values like `00412` keep their leading zeros. ## Merged cells Spreadsheets filter and sort better without merged cells, so docbeast unmerges them. A value that covers several rows is repeated on each of those rows. A value that covers several columns stays in the first column, and the other columns are blank. ## Excel The `.xlsx` file has one sheet for each table, or a sheet of text lines when a page has no table: - `Page 1` for a page's only table. - `Page 2 table 1`, `Page 2 table 2` when a page has several. - `Page 2 text` for text beside a table, or `Page 2` for a page with only text. In `table` mode, a page with a table returns only that table, so titles, dates and other details around it are left out. Use `mode=text` when you need those. Text becomes one row per line, split into columns on tabs or runs of two or more spaces. Plain numbers such as `47,000` or `-12.50` become numeric cells. Part numbers with leading zeros, like `00412`, and digit runs longer than 15 digits stay as text, so they aren't changed. ## CSV The `.csv` file has the same sheets one after another, separated by a blank line. A scan can contain anything, so a cell a spreadsheet would run as a formula gets a leading apostrophe. That covers cells starting with `=`, `+`, `@`, a tab or a return, and cells starting with `-` that aren't numbers. ## Text mode Use `mode=text` for documents without tables, such as letters. The result has the page's text in `text`, and in Excel and CSV each line becomes a row.