Overview
The API runs the same table extraction as the website. You post one image per request and it answers with
the detected table, either as rows of text in JSON or as a ready-made .xlsx file.
Every request is plain HTTPS and every reply, apart from the spreadsheet download, is JSON.
Base URL: https://imagetoexcel.net/api/v1
API plans are sold separately from the web plans and have their own credit balance. Create and manage keys in your profile.
Authentication
Send your key with every request, either as a bearer token or in an X-API-KEY header:
Authorization: Bearer YOUR_API_KEY
# or
X-API-KEY: YOUR_API_KEY
Each account has two kinds of key:
- Sandbox key (starts with
sk_test_). Free, available from signup, and it never reads your image. It always returns the same sample table, so you can build and test your integration without spending credits. - Live key (starts with
sk_live_). Reads your image and uses credits. It needs an active API plan.
Keep keys on your server. If one leaks, revoke it from your profile and create a new one.
Convert an image
POST https://imagetoexcel.net/api/v1/image-to-excel
Parameters
Send a multipart/form-data body. Provide the image in exactly one of the first three ways.
| Field | Type | Description |
|---|---|---|
image | file | The image, uploaded as a file. |
base64 | string | The image as base64. A full data: URI or the bare base64 string both work. |
image_url | string | A public URL we download the image from. The host must answer within 15 seconds. |
output_type | string | json (default) returns the rows. file returns an .xlsx download. |
filename | string | Optional name for the downloaded file, up to 120 characters. Only used with output_type=file. |
Accepted image types: JPEG, PNG, WebP, BMP, GIF, TIFF, HEIC and HEIF. PDFs are not accepted by the API. The type is detected from the file contents, not from its name.
Examples
cURL
curl -X POST "https://imagetoexcel.net/api/v1/image-to-excel" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "image=@invoice.jpg"
Download as Excel
curl -X POST "https://imagetoexcel.net/api/v1/image-to-excel" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "image_url=https://example.com/report.png" \
-F "output_type=file" \
-o report.xlsx
JavaScript
const form = new FormData();
form.append("image", fileInput.files[0]);
const res = await fetch("https://imagetoexcel.net/api/v1/image-to-excel", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
body: form,
});
const data = await res.json();
console.log(data.rows);
Python
import requests
res = requests.post(
"https://imagetoexcel.net/api/v1/image-to-excel",
headers={"Authorization": "Bearer YOUR_API_KEY"},
files={"image": open("invoice.jpg", "rb")},
)
print(res.json()["rows"])
Response
With output_type=json, rows is a list of rows and each row is a list of cell values in column order:
{
"error": false,
"sandbox": false,
"rows": [
["Date", "Description", "Debit", "Credit"],
["2026-01-09", "ACME Supplies Ltd", "312.40", ""]
],
"meta": { "row_count": 2, "column_count": 4 }
}
Cell values are returned as text exactly as read from the image. We do not convert or round numbers, so parse them on your side.
With output_type=file the response body is the spreadsheet itself, sent as an attachment.
A successful live request uses 1 credit.
If no table can be read from the image you get a no_table_found error and no credit is used.
Account and balance
GET https://imagetoexcel.net/api/v1/account
Returns your plan limits and remaining credits, so an integration can show usage or slow down before it runs out.
curl "https://imagetoexcel.net/api/v1/account" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"error": false,
"plan": {
"name": "Plus",
"tier": "plus",
"max_file_mb": 20,
"requests_per_minute": 30
},
"credits": {
"remaining": 940,
"allowance": 1000,
"renews_at": "2026-11-01T00:00:00+00:00"
}
}
Errors
Failed requests return a non-2xx status and a JSON body with a stable code to branch on and a readable message:
{
"error": true,
"code": "invalid_api_key",
"message": "Invalid API key."
}
| Status | Code | Meaning |
|---|---|---|
| 401 | missing_api_key |
No key was sent. |
| 401 | invalid_api_key |
The key does not exist or has been revoked. |
| 402 | insufficient_credits |
Your credits for this month are used up. |
| 403 | no_active_plan |
This live key has no active API plan. Use the sandbox key or subscribe. |
| 422 | missing_image |
None of image, base64 or image_url was sent. |
| 422 | invalid_input |
The upload, base64 value or image_url could not be read or downloaded. |
| 422 | file_too_large |
The image is bigger than your plan allows. |
| 422 | unsupported_type |
The file is not one of the accepted image types. |
| 422 | no_table_found |
No table could be read from the image. No credit is used. |
| 429 | rate_limited |
Too many requests this minute for your plan. |
A malformed output_type, image_url or filename
is rejected with status 422 and a message plus an errors object naming the field.
Limits and credits
One image costs 1 credit. Credits renew in full every month and unused ones do not roll over. File size and request rate depend on your API plan:
| Plan | Max image size | Requests per minute |
|---|---|---|
| Lite | 10 MB | 15 |
| Plus | 20 MB | 30 |
| Pro | 30 MB | 50 |
Limits are counted per key, so two keys on one account each get their own request budget.
When you receive a 429, wait a minute and retry.
Current monthly prices are on the pricing section
(pick the API tab); for more than the largest plan, contact us.