TranslateKaro API
Programmatic access to the same document-translation pipeline the web app uses: upload a scanned PDF, get back a translated document. OCR extracts the text from the scan; machine translation converts it into your target language.
Authentication
Send your key in the X-API-Key header on every request.
Keys are per-user — generate or regenerate yours from the
API Access card on your
dashboard. A key is
shown once, at generation time; only its prefix is shown afterwards.
An X-API-Key request is authenticated independently of your
browser session and does not need a CSRF token. If you call these
endpoints from a logged-in browser session instead (no X-API-Key
header), the usual session CSRF protection applies.
An invalid X-API-Key always gets a JSON 401.
If you send no key at all (and have no browser session), you must also
send Accept: application/json to get a JSON 401
back — without it you get a browser-style 302 redirect to
/login instead, so API clients should always send that
header. See Errors below.
Rate limits
| Endpoint | Limit |
|---|---|
POST /estimate | 10 / minute |
GET /status/<job_id> | 60 / minute |
GET /download/<job_id> | 30 / minute |
GET /preview/<job_id> | 30 / minute |
GET /preview-source/<job_id> | 30 / minute |
| everything else | 100 / hour (default) |
Limits are keyed per user when a valid X-API-Key is
presented, otherwise per IP address. Exceeding a limit returns
429.
Uploading a document
POST /estimate takes a multipart/form-data body:
| Field | Required | Notes |
|---|---|---|
pdf | yes | The PDF file. Must be a valid PDF, ≤ 500 MB, ≤ 2000 pages. |
target_lang | no (default en) |
One of the target language codes below. |
source_lang | no (default hi) |
The OCR hint for the document's language — one of the document language codes below. |
Target languages
en — Englishhi — Hindibn — Bengalita — Tamilte — Telugukn — Kannadaml — Malayalammr — Marathigu — Gujaratipa — Punjabiod — OdiaDocument (source) languages
hi — Hindibn — Bengalita — Tamilte — Telugukn — Kannadaml — Malayalammr — Marathigu — Gujaratipa — Punjabiod — Odiaen — EnglishEndpoints
| Method & path | Description |
|---|---|
POST /estimate |
Upload a PDF, get back a job id, page count and price. |
POST /billing/start-free/<job_id> |
Start the job on a free trial (first 2 uploads per account, ≤ 5 pages each), if you're still eligible. |
POST /billing/create-order/<job_id> |
Create a payment order for the job's estimated cost. Returns a Razorpay order id and key id for use with Razorpay Checkout. |
POST /billing/verify-payment |
Confirm a completed Razorpay Checkout payment and start the job. |
GET /status/<job_id> |
Poll job status and progress. |
GET /download/<job_id>?format=pdf|html |
Download the translated document once the job is complete.
Defaults to pdf; falls back to HTML if no PDF
is available. |
GET /preview/<job_id> |
Render the translated document as HTML, for viewing inline rather than downloading. |
GET /preview-source/<job_id> |
Render the pre-translation (rebuilt or raw OCR) HTML, for comparing against the translated output. |
Paying by card happens through Razorpay's own Checkout widget in a
browser — this API does not accept card details directly. The free
trial path (/billing/start-free/<job_id>) is the only
fully headless way to start a job.
Response shapes
POST /estimate responds with:
{
"job_id": "…",
"filename": "…",
"target_lang": "en",
"target_lang_name": "English",
"source_lang": "hi",
"source_lang_name": "Hindi",
"page_count": 12,
"price_per_page": 15,
"total_price": 180,
"total_price_paise": 18000,
"currency": "INR",
"pricing_tiers": [{"up_to": 20, "rate": 15}, …],
"trial_eligible": true,
"free_uploads_remaining": 2,
"trial_page_limit": 5,
"trial_pages": 5,
"gst_enabled": false
}
When GST is enabled for your account, gst_rate_percent,
gst_amount, total_with_gst and
total_with_gst_paise are added.
GET /status/<job_id> responds with:
{
"status": "processing",
"step": "uploading",
"detail": "Starting...",
"progress": 42,
"pages_done": 5,
"pages_total": 12
}
pages_done/pages_total/progress are
only present once the job has started; stuck: true is added
if the job appears wedged.
Status values
| Status | Meaning |
|---|---|
pending_payment |
Order created; waiting for the payment to be confirmed —
seen from /status only after the 24 h live-state
window has expired (before that the live status is
estimated). |
processing |
The document is being translated. |
complete |
Translation finished; the result is ready to download. |
error |
Translation failed. Paid jobs are refunded automatically. |
interrupted |
A worker restart interrupted the job; it resumes automatically. |
estimated is a job's actual status immediately after
/estimate — the state /billing/start-free and
/billing/create-order expect the job to be in. But
/status returns 404 for it until then: no
order or trial attempt has been created for the job yet, so there's no
record to look up. Once /billing/create-order has been
called, /status starts working and reports
estimated until the payment is confirmed, when it moves to
processing. The free trial path
(/billing/start-free) skips this window entirely and moves
the job straight to processing.
Errors
Errors are JSON: {"error": "…"}.
| Code | When |
|---|---|
400 |
Bad request — missing/invalid file, unsupported language code, malformed job id, etc. |
401 |
Invalid X-API-Key, or no key and no session.
The no-auth case only responds with this JSON 401
when the request sends Accept: application/json
(or a JSON body) — otherwise it's a 302 redirect
to /login, so always send that header. |
403 |
Forbidden — e.g. email not yet confirmed, free trial exhausted, or a job that belongs to a different account. |
404 |
No such job, or no output file for it yet. |
413 |
Upload exceeds 500 MB. |
429 |
Rate limit exceeded. |
Walkthrough
Accept: application/json is included on every call below —
without it, an unauthenticated or unauthorized request gets a browser
redirect instead of a JSON error (see Errors above).
# 1. Estimate — upload the PDF, get a job id and price
curl -X POST https://translatekaro.com/estimate \
-H "X-API-Key: $TK_API_KEY" -H "Accept: application/json" \
-F "pdf=@document.pdf" \
-F "target_lang=en" \
-F "source_lang=hi"
# => {"job_id": "abc123...", "trial_eligible": true, "total_price": 180, ...}
# 2a. Start it on the free trial, if trial_eligible is true
curl -X POST https://translatekaro.com/billing/start-free/abc123... \
-H "X-API-Key: $TK_API_KEY" -H "Accept: application/json"
# 2b. Otherwise, pay: create an order, complete Razorpay Checkout in a
# browser with the returned order_id/key_id, then verify it
curl -X POST https://translatekaro.com/billing/create-order/abc123... \
-H "X-API-Key: $TK_API_KEY" -H "Accept: application/json"
# ... complete payment via Razorpay Checkout ...
curl -X POST https://translatekaro.com/billing/verify-payment \
-H "X-API-Key: $TK_API_KEY" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"razorpay_order_id": "...", "razorpay_payment_id": "...", "razorpay_signature": "..."}'
# 3. Poll status until complete
curl -H "X-API-Key: $TK_API_KEY" -H "Accept: application/json" \
https://translatekaro.com/status/abc123...
# 4. Download the result
curl -H "X-API-Key: $TK_API_KEY" -H "Accept: application/json" \
-o translated.pdf \
"https://translatekaro.com/download/abc123...?format=pdf"