From an image to your workflow
Submit an image, follow its conversion, and download structured results through a simple REST API.
Create an API keyQuickstart
Send a JPG, PNG, BMP or TIFF image as multipart form data. The API returns 202 with a job ID. tableOnly=true extracts tables; false also extracts surrounding text.
curl -X POST 'https://jpg2excel.app/api/v1/jobs' \
-H "Authorization: Bearer $JPG2EXCEL_API_KEY" \
-H 'Idempotency-Key: invoice-2026-10-001' \
-F 'file=@table.jpg' \
-F 'tableOnly=true'{
"code": 0,
"msg": "OK",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"filename": "table.jpg",
"createdAt": "2026-10-08T08:00:00.000Z",
"completedAt": null,
"resultExpiresAt": null,
"creditsUsed": 0,
"error": null,
"resultFormats": [],
"statusUrl": "/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000",
"resultUrl": null
}
}This Python example submits a file, waits for completion and saves an Excel workbook. Set JPG2EXCEL_API_KEY in your server environment first.
import os
import time
import uuid
import requests
base = "https://jpg2excel.app"
headers = {"Authorization": f"Bearer {os.environ['JPG2EXCEL_API_KEY']}"}
# Keep this value if you retry the same submission.
submission_key = str(uuid.uuid4())
with open("table.jpg", "rb") as image:
response = requests.post(
f"{base}/api/v1/jobs",
headers={**headers, "Idempotency-Key": submission_key},
files={"file": ("table.jpg", image, "image/jpeg")},
data={"tableOnly": "true"},
timeout=60,
)
response.raise_for_status()
job = response.json()["data"]
deadline = time.monotonic() + 600
while job["status"] in ("queued", "processing"):
if time.monotonic() > deadline:
raise TimeoutError("Conversion is still running; query its job ID later.")
time.sleep(2)
response = requests.get(base + job["statusUrl"], headers=headers, timeout=30)
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", "5")))
continue
response.raise_for_status()
job = response.json()["data"]
if job["status"] != "succeeded":
raise RuntimeError(job.get("error") or job["status"])
result = requests.get(
base + job["resultUrl"], headers=headers,
params={"format": "xlsx"}, timeout=60,
)
result.raise_for_status()
with open("result.xlsx", "wb") as output:
output.write(result.content)Authentication
Use a Plus or Enterprise API key in the Authorization header. Team keys use team credits. Store secrets on your server; never expose them in browser code.
Authorization: Bearer j2e_live_YOUR_SECRET_KEYjobs:write submits jobs. jobs:read reads job status, downloads results and checks usage. Limit each key to the permissions your integration needs.
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /api/v1/jobs | Submit an image |
| GET | /api/v1/jobs/{id} | Read job status |
| GET | /api/v1/jobs/{id}/result | Download structured output |
| GET | /api/v1/usage | Read available credits and limits |
Conversion jobs
Poll the status URL until the job succeeds or fails. Start with a 2-second interval and back off when requests are rate limited.
curl 'https://jpg2excel.app/api/v1/jobs/JOB_ID' \
-H "Authorization: Bearer $JPG2EXCEL_API_KEY"Send an Idempotency-Key for each logical submission. Reuse it when retrying the same file and options so the job is not created or charged twice.
A repeated key returns the original job with HTTP 200. Reusing a key with a different file or options returns HTTP 409. Idempotency keys are scoped to the workspace.
Download results
Download XLSX, CSV or JSON after success. Use resultExpiresAt from the job response to know how long the result remains available.
curl 'https://jpg2excel.app/api/v1/jobs/JOB_ID/result?format=xlsx' \
-H "Authorization: Bearer $JPG2EXCEL_API_KEY" \
--output result.xlsxxlsx
Editable Excel workbook
csv
First table as CSV for data pipelines
json
Structured tables in a JSON envelope
Results are available for 24 hours after completion. Save them to your own storage. TIFF uploads must be single-page; PDF is not supported by this endpoint.
Credits and limits
Web and API conversions share credits. Successful jobs spend credits; failed jobs release their reservation. Your plan sets file size, concurrency and request limits. API jobs always require credits.
curl 'https://jpg2excel.app/api/v1/usage' \
-H "Authorization: Bearer $JPG2EXCEL_API_KEY"API key limits reset each UTC calendar month. Member limits follow the team's monthly credit renewal and count completed and reserved credits. Limits do not add credits; a zero member limit blocks new conversions.
Enterprise includes 3 seats, including the owner. Additional seats cost $5/month or $50/year each. Team members share credits and concurrency limits; only the owner and admins manage team keys.
Errors and retries
Errors use the same JSON envelope: code, msg and data. Use the HTTP status and error code to decide whether to retry.
{
"code": 1006,
"msg": "Workspace request rate limit reached.",
"data": null
}| HTTP | code | What to do |
|---|---|---|
| 400 | 1001 / 2004 / 2005 | Check the request fields, file and options before retrying. |
| 401 | 1002 | Check your key. Expired and revoked keys cannot authenticate. |
| 402 | 3002 / 3003 | Add credits, or wait for the key or member monthly limit to reset. |
| 403 | 1003 | Check key scopes and the workspace subscription. |
| 404 / 410 | 1004 / 2007 | Check the job ID and workspace; expired results cannot be downloaded. |
| 409 | 1005 | The result is not ready, or the idempotency key was used for different input. |
| 413 / 415 | 2002 / 2003 | Reduce the file size or use a supported image format. |
| 429 | 1006 | Wait for Retry-After, then retry. Reduce request rate or concurrency. |
| 503 | 1007 | Retry with backoff and the same idempotency key. |
A failed conversion is reported in the job's error field, even when the status request itself returns HTTP 200. Codes 2006, 2008 and 2009 indicate conversion failure, timeout and no detected table.