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

EndpointLimit
POST /estimate10 / 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 else100 / 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:

FieldRequiredNotes
pdfyes The PDF file. Must be a valid PDF, ≤ 500 MB, ≤ 2000 pages.
target_langno (default en) One of the target language codes below.
source_langno (default hi) The OCR hint for the document's language — one of the document language codes below.

Target languages

en — English
hi — Hindi
bn — Bengali
ta — Tamil
te — Telugu
kn — Kannada
ml — Malayalam
mr — Marathi
gu — Gujarati
pa — Punjabi
od — Odia

Document (source) languages

hi — Hindi
bn — Bengali
ta — Tamil
te — Telugu
kn — Kannada
ml — Malayalam
mr — Marathi
gu — Gujarati
pa — Punjabi
od — Odia
en — English

Endpoints

Method & pathDescription
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

StatusMeaning
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": "…"}.

CodeWhen
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"