translation.legal logo translation.legal

Partner API Instructions

This API is for server-to-server document processing. Use POST /api/v1/jobs for the full one-step pipeline or POST /api/v1/workflows for partial Advanced Mode workflows.

This is the same public guide linked from the login page and the signed-in account menus.

Base workflow

  1. Confirm your partner identity and limits with GET /api/v1/account.
  2. Check backlog and recent activity with GET /api/v1/jobs/summary.
  3. Create a full one-step job with POST /api/v1/jobs or a partial workflow with POST /api/v1/workflows.
  4. Optionally reconcile recent jobs with GET /api/v1/jobs.
  5. Inspect the job timeline with GET /api/v1/jobs/{job_id}/events.
  6. Poll GET /api/v1/jobs/{job_id} or wait for a webhook.
  7. Inspect step outputs with GET /api/v1/jobs/{job_id}/artifacts.
  8. Inspect webhook delivery with GET /api/v1/jobs/{job_id}/webhook.
  9. Optional: cancel an active job with POST /api/v1/jobs/{job_id}/cancel.
  10. Optional: purge a terminal job with DELETE /api/v1/jobs/{job_id}.
  11. Download the completed file from GET /api/v1/jobs/{job_id}/result.

Important defaults

  • Server-to-server only. It is not designed for browser-side API keys.
  • POST /api/v1/jobs always runs the full 1,2,3,4 pipeline.
  • POST /api/v1/workflows accepts 1 to 3 ascending steps such as 1,3 or 2,3,4.
  • url is supported only when Step 1 is requested and accepts a public HTML page or a direct public PDF URL.
  • Workflows that start at Step 2, Step 3, or Step 4 must upload a Markdown file.
  • Supported outputs: docx, html, pdf.

Authentication

Send the partner API key in the Authorization header:

Authorization: Bearer tlapi_...

API keys are provisioned by running python scripts/create_partner_api_key.py ... against the target environment.

Schema and Interactive Docs

The live app also exposes machine-readable and interactive docs generated from the FastAPI routes:

  • /openapi.json: machine-readable OpenAPI schema
  • /docs: interactive Swagger UI

Treat this page as the human-readable public guide. Use /docs for live request/response schemas and /openapi.json for client generation.

If you generate a client SDK, prefer the stable partner operation IDs: getPartnerAccount, createPartnerJob, createPartnerWorkflow, listPartnerJobs, getPartnerJobSummary, getPartnerJobEvents, getPartnerJob, listPartnerJobArtifacts, getPartnerJobArtifact, getPartnerJobWebhookStatus, cancelPartnerJob, purgePartnerJob, and getPartnerJobResult.

Inspect Your Partner Account

curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/account

This returns the authenticated partner ID, display name, configured rate limit, concurrent-job limit, last-used timestamp, and convenience links to the live docs.

Response fields:

  • partner_id, name, contact_email, active
  • rate_limit_per_minute, concurrent_job_limit, last_used_at
  • api_docs_url, openapi_url

Get a Job Summary

curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/summary

This returns partner-scoped counts by public job status, recent 24-hour activity, and the current available concurrency derived from your configured job limit.

Response fields:

  • counts.total, counts.active, counts.queued, counts.processing, counts.complete, counts.error, counts.cancelled
  • recent_24h.window_hours, recent_24h.created, recent_24h.completed, recent_24h.errored, recent_24h.cancelled
  • concurrent_job_limit, available_concurrency

Create a Full One-Step Job

curl -X POST https://dev.translation.legal/api/v1/jobs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: retry-20260329-001" \
  -F file=@contract.pdf \
  -F source_lang=th \
  -F target_lang=en \
  -F output_format=docx \
  -F external_job_id=partner-123

Required form fields:

  • source_lang
  • target_lang
  • output_format
  • Exactly one of file or url

Optional form fields:

  • external_job_id
  • webhook_url

Accepted sources:

  • file: uploaded document input supported by the current Step 1 profile
  • url: either a public HTML page or a direct public PDF URL

Direct PDF URLs are downloaded through the same bounded intake path used for uploaded PDFs and remain subject to the same size and page limits. Private or internal redirect targets are rejected.

Create a Partial Workflow

curl -X POST https://dev.translation.legal/api/v1/workflows \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: retry-20260417-001" \
  -F steps=1,3 \
  -F file=@contract.pdf \
  -F source_lang=th \
  -F target_lang=en \
  -F external_job_id=partner-124

Supported step patterns:

  • 1, 1,2, 1,3, 1,4
  • 1,2,3, 1,2,4, 1,3,4
  • 2, 2,3, 2,4, 2,3,4
  • 3, 3,4, 4

Rules:

  • Steps must be ascending and must not repeat.
  • Maximum 3 steps.
  • Use POST /api/v1/jobs for the full 1,2,3,4 pipeline.
  • If Step 1 is included, send exactly one of file or url.
  • If Step 1 is omitted, upload a Markdown file in file.
  • source_lang is required for Step 1, Step 2, or Step 3.
  • target_lang is required for Step 3.
  • output_format is required only for Step 4.

If a workflow includes Step 1 but skips Step 2, the job surfaces a warning that OCR cleanup was skipped before downstream processing.

Safe Retries / Idempotency

If your network times out after calling POST /api/v1/jobs, retry with the same Idempotency-Key header instead of submitting a brand-new request.

  • Same partner + same key + same request payload: the original job is reused
  • Same partner + same key + different payload: the API returns 409
  • Replay responses include idempotency_replay=true

Use short, unique retry keys such as retry-20260329-001. The API accepts letters, numbers, dots, underscores, colons, and hyphens.

List and Reconcile Jobs

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs?status=complete,cancelled&limit=20&offset=0"

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs?external_job_id=partner-123"

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs?created_from=2026-03-28&created_to=2026-03-29"

Supported query parameters:

  • status: optional comma-separated public statuses: queued, processing, complete, error, cancelled
  • external_job_id: optional exact match against your partner-supplied identifier
  • created_from / created_to: optional inclusive created-at bounds using ISO dates or datetimes
  • limit: optional page size, default 20, max 100
  • offset: optional zero-based offset for pagination

The response includes jobs, count, total, limit, offset, and has_more.

Inspect Job Events

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs/$JOB_ID/events?limit=100"

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs/$JOB_ID/events?level=WARNING&limit=50"

The event timeline is built from the stored task logs for the parent pipeline and any child step tasks. Each event includes a timestamp, level, message, and source label such as pipeline or step2.

Supported query parameters:

  • level: optional exact log level filter
  • limit: optional max events, default 100, max 500

Status and Result

curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs

curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID

curl -H "Authorization: Bearer $API_KEY" \
  "https://dev.translation.legal/api/v1/jobs/$JOB_ID/events?limit=100"

curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID/webhook

curl -X POST -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID/cancel

curl -X DELETE -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID

curl -L -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID/result \
  -o output.docx

Wait for status=complete and output_ready=true before calling the result endpoint. If the file is not ready yet, the result endpoint returns 409.

Job status now also includes workflow_type, requested_steps, completed_steps, and per-step artifacts. Artifact ids are stable labels such as step1, step2, step3, and step4.

Each artifact entry includes:

  • artifact_id, step_number, artifact_type
  • filename, content_type, download_url
  • status, is_final
curl -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID/artifacts

curl -L -H "Authorization: Bearer $API_KEY" \
  https://dev.translation.legal/api/v1/jobs/$JOB_ID/artifacts/step3 \
  -o translated.md

Cancellation is supported for queued or in-progress jobs. Cancelling a completed or failed job returns 409, and a cancelled job will no longer expose result_url.

Purge is supported for terminal jobs only. Once a purge succeeds, later status and result requests for that job return 404.

Webhook Signing

When webhook_url is supplied, terminal job updates are signed with the partner’s webhook secret.

  • X-Translation-Legal-Event: job.completed, job.cancelled, or job.failed
  • X-Translation-Legal-Timestamp: Unix timestamp
  • X-Translation-Legal-Signature: sha256=<hex>

Signature input: timestamp + "." + raw_json_body

Verify signatures in Python:

import hashlib
import hmac

def verify_signature(webhook_secret: str, timestamp: str, raw_body: bytes, header_value: str) -> bool:
    expected = hmac.new(
        webhook_secret.encode("utf-8"),
        f"{timestamp}.".encode("utf-8") + raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(header_value, f"sha256={expected}")

Verify signatures in Node.js:

import crypto from "node:crypto";

export function verifySignature(webhookSecret, timestamp, rawBody, headerValue) {
  const expected = crypto
    .createHmac("sha256", webhookSecret)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(headerValue),
    Buffer.from(`sha256=${expected}`)
  );
}

You can inspect the last recorded delivery state for a job with GET /api/v1/jobs/{job_id}/webhook. The response includes whether a webhook was configured and the last recorded delivery state for terminal webhook events.

Retention

The current cleanup policy keeps partner-facing final outputs, task logs, and terminal task records for about 30 days. Temporary intermediates are retained for shorter windows, typically around 3 days.

If you need earlier deletion for a specific partner job, use DELETE /api/v1/jobs/{job_id} after that job is terminal.

Treat the API as an asynchronous processing interface, not as permanent document storage.

Understanding Review Warnings

Review metadata is split into English explanations and source-language evidence:

  • warnings: short English warning strings
  • review_findings: structured English review issues
  • review_targets: source-language snippets copied from the original document

If review_targets contains Thai or another source script, that does not mean the API is returning untranslated UI text. Those snippets are included so a reviewer can compare the flagged references against the original source PDF.

Errors to Expect

  • 400: invalid input, unsupported language pair, unsupported output format
  • 401: missing or invalid API key
  • 404: job not found or not owned by this partner
  • 409: result not ready yet, job cancelled, or an Idempotency-Key was reused with a different payload
  • 429: rate limit or concurrent-job limit reached
  • 503: required conversion tooling is unavailable on the server