iSomor

API documentation

Authentication, endpoint paths, parameters, responses and recovery in one reference.

Access & authentication

Email your project, verified iSomor account email, document workflow and expected volume. We will reply with the review outcome. On approval, receive credentials, the base URL and an initial allowance together; no second key-creation step. Send Authorization: Bearer <API_KEY> with every request. Store the key only in server-side environment variables, never cookies, URLs, frontends or AI prompts. Contact support for rotation or revocation without sending the full key.

The command below sets the production ISOMOR_API_BASE_URL, including /api/isomor/v1 without a trailing slash. Set ISOMOR_API_KEY using your server-side secret manager; keep the real key out of command history and code. The curl examples read these variables and prompt you to set any missing values. Use Content-Type: application/json for JSON and multipart/form-data for uploads, with a client-generated boundary. Responses use JSON and HTTP status codes distinguish success from errors.

export ISOMOR_API_BASE_URL="https://tryisomor.com/api/isomor/v1"
Email for API access ↗

support@tryisomor.com

Call sequence

Read capabilities → upload PDF → use the returned id as file_id → create a job and save job_id → poll status → get download links. Check allowance before creating if needed, but a balance read is not a reservation. Follow the idempotency and retry rules below to avoid duplicate jobs.

Downloads & quick start

Import the OpenAPI file into a compatible development tool; baseUrl defaults to the production API URL. The Python example requires Python 3.10 or newer, with no third-party dependencies. Configure both environment variables above before running it.

This command translates page 1, uses at most 1 credit and retrieves translated and bilingual PDFs. --submit uploads the file and submits a translation; without --submit or --resume, no requests are sent. When changing the page selection, review --max-credits too. If the estimate exceeds the cap, the file is uploaded but no translation is created.

python3 translate_pdf.py \
  --file ./sample.pdf --target zh --pages 1 \
  --max-credits 1 --output ./translation-001 --submit

Resume the same job after interruption

Keep the output directory and use credentials for the same project. The example saves the original request and idempotency key; known jobs are queried, not recreated. It stops when an unknown creation outcome is outside the safe retry window. Existing files with matching saved hashes are skipped, and expired download links are refreshed. Each run waits up to 600 seconds by default; --timeout supports up to 3600 seconds.

python3 translate_pdf.py --output ./translation-001 --resume

The output directory contains private PDFs and state.json recovery data. Do not commit it to Git or share it publicly. Credentials are not saved in state or forwarded to download URLs. Existing files are not overwritten; uploads without a returned file ID are not retried automatically.

GET/capabilities

Read capabilities and limits

Read supported languages, output formats and credential-specific limits before integration. Use the limits returned for your credentials.

Required scope: capabilities:read

Request parameters

No path, query or body parameters; Bearer authentication is still required.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request GET "${ISOMOR_API_BASE_URL}/capabilities" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}"

Response fields

source_languages / target_languagesstring[]
Available language codes; auto is only a source language.
input_mime_types / output_formatsstring[]
Text-based PDFs only; output is translated or bilingual.
credits_per_pageinteger
Credits consumed per text PDF page.
limitsobject
Positive integers: max_file_bytes, max_pages, max_concurrent_jobs, requests_per_minute. max_storage_bytes is the combined input allowance for sources and selected-page copies. Use the live values.

200 · Response example

{
  "source_languages": [
    "auto",
    "en",
    "zh"
  ],
  "target_languages": [
    "en",
    "zh"
  ],
  "input_mime_types": [
    "application/pdf"
  ],
  "credits_per_page": 1,
  "output_formats": [
    "translated",
    "bilingual"
  ],
  "limits": {
    "max_file_bytes": 10485760,
    "max_pages": 20,
    "max_concurrent_jobs": 1,
    "requests_per_minute": 30,
    "max_storage_bytes": 104857600
  }
}
POST/files

Upload a PDF

Upload one PDF and receive a validated file_id for translation. This does not start translation; each upload creates a separate file record.

Required scope: files:write · multipart/form-data

Request parameters

filebinary · required
PDF bytes, not a local-path string or a remote URL. The document must be an unencrypted original digital PDF; scans are not supported, even after OCR.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request POST "${ISOMOR_API_BASE_URL}/files" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}" \
  --form 'file=@./sample.pdf;type=application/pdf'

Response fields

idstring
Opaque file ID owned by the integration identity; pass it as file_id.
filename / media_typestring
Sanitized filename and application/pdf.
page_countinteger
Validated total page count, greater than zero.

201 · Response example

{
  "id": "file_example",
  "filename": "sample.pdf",
  "media_type": "application/pdf",
  "page_count": 3
}
POST/translations

Create a translation job

Validate the file, languages, pages and allowance, then enqueue asynchronously. A 202 response means accepted, not translated. Idempotency-Key is required and must be reused for retries.

Required scope: translations:write · application/json

Request parameters

file_idstring · required
File ID uploaded by this integration identity.
target_languagestring · required
Target code from /capabilities; auto is not valid.
source_languagestring · optional
Source language code; defaults to auto.
pagesstring · optional
Omit for all pages; e.g. 1-3,5. One-based, inclusive ranges within the document; duplicate pages count once. Outputs contain only selected pages in original order.
output_formatsstring[] · optional
Non-empty, unique list of translated and/or bilingual; defaults to both.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request POST "${ISOMOR_API_BASE_URL}/translations" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: example-request-001' \
  --data '{
  "file_id": "file_example",
  "target_language": "zh",
  "source_language": "en",
  "pages": "1-3",
  "output_formats": [
    "translated",
    "bilingual"
  ]
}'

Response fields

id / file_idstring
Job ID and source file ID; persist the job ID for later queries.
statusstring
Initially queued; an idempotent replay can return the job's current state.

202 · Response example

{
  "id": "job_example",
  "file_id": "file_example",
  "status": "queued"
}
GET/translations/{job_id}

Read job status

Poll a persistent job ID. For queued / running, wait the seconds in Retry-After before polling again. Fetch results on succeeded; stop and inspect error on failed.

Required scope: translations:read

Request parameters

job_idpath · required
The job ID returned by creation, not file_id.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request GET "${ISOMOR_API_BASE_URL}/translations/job_example" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}"

Response fields

id / file_idstring
Job and source file IDs.
statusenum
queued → running → succeeded or failed. succeeded means results are ready; cancellation is not supported.
errorobject | null
null unless failed; then code and message, without internal traces or document content.

200 · Response example

{
  "id": "job_example",
  "file_id": "file_example",
  "status": "succeeded",
  "error": null
}
GET/translations/{job_id}/results

Get result files

Available after succeeded. Returns 409 result_not_ready while pending or 409 job_failed after failure. Refresh expired links here; do not create another translation.

Required scope: translations:read

Request parameters

job_idpath · required
Completed job ID owned by the integration identity.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request GET "${ISOMOR_API_BASE_URL}/translations/job_example/results" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}"

Response fields

job_idstring
Job that owns these results.
files[].formatenum
translated or bilingual, matching requested formats.
files[].urlstring · URI
Temporary HTTPS download URL; sensitive access material, never log it.
files[].expires_atstring · date-time
Link expiry in RFC 3339 UTC; download before expiry and store securely.

200 · Response example

{
  "job_id": "job_example",
  "files": [
    {
      "format": "translated",
      "url": "https://example.com/results/translated.pdf",
      "expires_at": "2026-09-10T12:00:00Z"
    },
    {
      "format": "bilingual",
      "url": "https://example.com/results/bilingual.pdf",
      "expires_at": "2026-09-10T12:00:00Z"
    }
  ]
}
GET/quota

Read API allowance

Read the API integration’s allowance snapshot. Allowance is checked and reserved when you create a job. API and MCP personal-account allowances are separate.

Required scope: quota:read

Request parameters

No path, query or body parameters; Bearer authentication is still required.

Request example

: "${ISOMOR_API_BASE_URL:?Set ISOMOR_API_BASE_URL}" &&
: "${ISOMOR_API_KEY:?Set ISOMOR_API_KEY}" &&
curl --request GET "${ISOMOR_API_BASE_URL}/quota" \
  --header "Authorization: Bearer ${ISOMOR_API_KEY}"

Response fields

unit"credits"
Allowance unit. Each text PDF page costs 1 credit; queries and uploads do not consume translation credits.
limit / used / reserved / remaininginteger ≥ 0
Granted / settled / held / available; remaining = limit − used − reserved, within the current allowance period.
expires_atdate-time | null
Allowance expiry; null means no configured expiry, not unlimited usage.

200 · Response example

{
  "unit": "credits",
  "limit": 100,
  "used": 20,
  "reserved": 10,
  "remaining": 70,
  "expires_at": null
}

Errors & retries

Errors use error.code, error.message and request_id. Share request_id with support, not full keys, download links or document content.

{
  "error": {
    "code": "quota_exceeded",
    "message": "The API allowance is insufficient."
  },
  "request_id": "req_example"
}
400invalid_request
Fix missing fields, JSON or idempotency key.
401invalid_api_key
Check key validity, expiry or revocation; do not retry automatically.
403insufficient_scope
Contact support for the required scope.
404not_found
Check the ID and integration owner; another owner's resource also returns 404.
409idempotency_conflict
Retry the original parameters and key; use a new key only for an intentional new job.
409result_not_ready / job_failed
Poll pending jobs; inspect error on failure instead of looping on results.
413 / 422file_too_large / unsupported_pdf
Correct the PDF size or content. Invalid languages or pages return 400 invalid_request; do not retry unchanged.
429quota_exceeded
Stop new jobs and request more allowance by email; a short wait will not restore it.
403quota_expired
Contact support to renew expired allowance; accepted jobs continue processing.
429concurrency_limit / storage_limit
Wait for active jobs when concurrency is full; contact support when input storage is full.
429rate_limited
Wait Retry-After seconds and back off; reuse the key for job creation.
503service_unavailable
Use exponential backoff; retain the original creation key to avoid duplicate work.

Idempotency window: 24 hours. One integration identity, endpoint and Idempotency-Key identify one job. Repeating the same parameters returns that job; changing parameters returns 409. On creation timeout or 5xx, retry only with the original key and parameters within the window. If the window expired and the job ID is unknown, contact support instead of blindly creating again. Upload retries may create another file but do not start translation.

Allowance & file limits

Approved API integrations receive an initial free allowance. Amount, expiry and conversion rules are confirmed by email. Request increases by email; there is no automatic billing. Allowance is reserved at job creation, settled on success and released on confirmed failure. Read /quota for your available balance. New jobs require sufficient allowance.

Supports original digital PDFs, asynchronous single-file jobs, and translated / bilingual PDFs. Scans are not supported, even after OCR. No OCR, Office, webhooks, batch creation or cancellation endpoint. File size, pages, concurrency and rate limits come from /capabilities. Download links expire and can be requested again; expiry does not mean file deletion. Text is sent to Google Gemini; read the privacy policy and verify results.

Request more allowance ↗
API documentation · iSomor