Request translations

This guide shows how to start translation jobs through the API, check their cost first, and handle the answers that need action: no subscription (402) and confirmation (409). Editors can do the same in the dashboard, see From the dashboard.

Translate everything that needs work

Send a delta job. It translates every segment of the site that is missing, stale or rejected in the writable target languages:

$ curl -X POST https://api.ponyglot.app/v1/jobs \
    -H "Authorization: Bearer $PONYGLOT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"type": "delta"}'

The answer is 202 Accepted with the job. Limit the languages with "languages": ["de", "fr"]; languages that aren’t writable target languages of the site are left out. If none is left, you get 422.

Translate specific units

Send a translate job with the units’ external keys:

{"type": "translate", "units": ["djangocms:page:42"]}

This covers the same segments as a delta job, limited to these units.

Add "force": true to retranslate every segment of the job’s scope, including translations that are approved, waiting for review or held back by QA. Each forced result gets a new result ID. force also works with a delta job, where it covers the whole site, so estimate such a job first.

Without force, segments held back by QA errors are not retranslated. Decide about them in the review queue.

Check the cost first

Add "estimate_only": true to any job request. Ponyglot answers 200 with what the job would translate and cost, and creates nothing:

{
  "languages": ["de", "fr", "it"],
  "estimated_segments": 120,
  "estimated_characters": 18400,
  "estimated_tm_segments": 35,
  "cost": {
    "characters": 18400,
    "included_characters": 500000,
    "used_characters": 212000,
    "reserved_characters": 0,
    "remaining_characters": 288000,
    "overage_characters": 0,
    "overage_cents": 0,
    "currency": "EUR",
    "requires_confirmation": false
  }
}

estimated_characters counts only billable characters. Segments found in the translation memory (estimated_tm_segments) and repeats of the same text within the job are free. Use the estimate to show a cost preview before a large backfill.

Handle 402: no subscription

Hosted translation needs a subscription that covers the site. Otherwise POST /v1/jobs answers 402 with a code:

code

Meaning

What to do

subscription_required

The organization has no subscription.

An owner chooses a plan under Billing.

subscription_inactive

The subscription is paused or canceled.

An owner checks Billing.

site_not_covered

The subscription doesn’t cover this site.

Pro: add the site to the subscription. Agency: the plan covers 10 sites.

Show detail to the user: it explains the problem in plain words.

Handle 409: confirmation required

A job needs explicit confirmation when it has more than 100,000 billable characters, or when it would use characters beyond the plan’s included volume. Then POST /v1/jobs answers 409:

{
  "detail": "This job needs confirmation: 240,000 characters will be translated.",
  "code": "confirmation_required",
  "estimate": {
    "characters": 240000,
    "included_characters": 500000,
    "used_characters": 150000,
    "reserved_characters": 0,
    "remaining_characters": 350000,
    "overage_characters": 0,
    "overage_cents": 0,
    "currency": "EUR",
    "requires_confirmation": true
  }
}
  1. Show the estimate to the user: characters, what’s already used this month and, if any, the characters beyond the included volume and their estimated charge (overage_cents).

  2. If the user agrees, send the same request again with "confirm": true.

Characters beyond the included volume are billed after the month. The rate is on the pricing page.

Note

Estimates count what queued and running jobs requested earlier are still expected to use (reserved_characters). If such a job turns out bigger than expected, the cost of your job can grow before it starts. A queued job whose cost has grown beyond what was confirmed fails when it starts. Request it again and confirm the new estimate.

Follow a job

Jobs run in the background, one at a time per site, in the order you requested them.

  • GET /v1/jobs/{id} shows the job: status (queued, running, succeeded, failed, cancelled), done_segments, failed_segments, qa_failed_segments, characters and errors.

  • GET /v1/jobs?active=true lists queued and running jobs; without the parameter you get the 20 most recent jobs.

  • POST /v1/jobs/{id}/cancel stops a job. Segments that are already translated are kept.

Results become available while the job runs. You don’t have to wait for the job to finish before you pull them.

errors lists problems per language, for example a language that no enabled engine supports. Those segments stay missing; fix the site’s engine settings and request a new job.

From the dashboard

Editors, admins and owners can start the same jobs in the dashboard:

  • On the site’s page, Translate stale & missing → drafts starts a delta job.

  • On a unit’s page (open it from Content), Retranslate stale → drafts starts a translate job for that unit.

If a job needs confirmation, the dashboard shows the estimate and asks you to confirm. Without a subscription, it links to Billing.