get started
Core concepts
The object model, how settings resolve, what each project status allows, and the asynchronous pattern behind every long-running call. Read this once: the Quickstart and the guides assume it.
The object hierarchy
Account your whole company on the platform
└── Organization a division, brand, region or major client
└── Org Unit a department, team or client account, where projects live
└── Project one job, with one source language
└── Resource one uploaded file
└── Work Unit file × workflow step × target language
└── Task a work unit with a person attached
Each level belongs to exactly one parent: an Organization to one Account, an Org Unit to one Organization. How you split them is up to you. Many accounts use one Org Unit per department, team or client, but there is no fixed rule.
The shape matters for two reasons: it decides what each person can see, since the level a user is added at sets how much of the account they have access to, and it decides where settings come from.
Learn more: Accounts, Organizations and Org Units · All about Organizational Units
Configuration is layered
Some settings are defined on the Account and inherited by its org units; others are set on the org unit itself. Not everything inherits, and the API has no single endpoint listing which does.
| Lives on | Examples |
|---|---|
| Account | Price lists, net rate settings |
| Organization | Translation memories and glossaries (created here, then associated with org units) |
| Org Unit | Currency, timezone, default locales, Quote Automation, autopilot, cost logfile type, and the translation memory and glossary associations |
The practical rule: read the org unit to see the effective settings, whatever their origin. GET /api/v3/client/{uuid} returns the values that will actually apply, and a null there generally means "inherited from the account":
{
"accountUuid": "adb57880-…",
"currency": "BRL",
"timezone": "America/Sao_Paulo",
"defaultSourceLanguage": "pt_br",
"sendQuoteAuto": true,
"projectAutomationEnabled": true,
"netRateSettings": null
}
That netRateSettings: null is the inheritance showing: no override here, so the account's settings apply. Price lists work the same way from the other direction: GET /api/v3/price-list returns them with accountUUID set and orgUnitUuid null, because they are defined once on the account and selected per org unit.
When you create a project with inferDefaultSettings=true, it is these resolved org unit settings that get copied onto the project.
Note that the API calls org units client. The endpoint is GET /api/v3/client, and inside a project payload the same object appears twice, as client and as organizationalUnit. They are the same object.
The Organization is thin by comparison: GET /api/v2/organization/{uuid} returns little more than a name, a country and the list of org units under it. It groups org units and owns the linguistic assets; it is not where project behaviour is configured.
Work units are the multiplication
You do not create work units one per file. One call creates resources × workflows × target locales of them:
[
{
"projectResourceUuid": "ef7ee1da-...",
"workflows": [
"TRANSLATION",
"PROOFREADING"
],
"targetLocales": [
"pt_br",
"es_es"
]
}
]
That single request produced four work units: TRANSLATION/pt_br, PROOFREADING/pt_br, TRANSLATION/es_es, PROOFREADING/es_es. Each one carries a sequence field, which is its workflow level: TRANSLATION is level 1, PROOFREADING level 2. Several download endpoints select content by workflow level, so this number matters.
Keep
sequencewhen you create the work units. The create response reports it, and so does the work unit search; List Project Work Units leaves it out. Store it with the UUIDs you are already keeping.For live progress,
GET /project/{uuid}/process-summaryis the endpoint to watch: it reports pre-translation as it happens.
Project locales
A project has one sourceLocale, set at creation and fixed afterwards.
It does not have target locales at creation: targetLocales comes back as []. Targets are derived from the work units you create. After creating the four work units above, the project reported:
"sourceLocale": "en_us",
"targetLocales": ["es_es", "pt_br"]
So "add a language to a project" means "create work units for that language".
Project status
Status controls what you are allowed to do. You change it with Change Project Status; the practical summary:
| Status | What it means | File/structure changes | Manual cost edits |
|---|---|---|---|
DRAFT | Being assembled | Allowed | Allowed |
PENDING | Quoted, awaiting approval | Blocked | Blocked |
APPROVED | Work is live, pre-translation runs | Blocked | Blocked |
DELIVERED | Work finished | Blocked | Blocked |
INVOICED / CANCELLED / DELETED | Terminal | Blocked | Blocked |
Continuous projects, which keep receiving files from a pipeline, have their own status, CONTINUOUS (see Creating projects from files).
Two things follow from that table:
- Add your files while the project is in
DRAFT. That is the status where files, work units and workflows are editable. To add one to a project that has moved on, bring it back toDRAFT, or start a new project for it. - Work starts at
APPROVED. That is when pre-translation runs and when people can pick up tasks: see Quickstart, step 7.
Quote Automation changes the flow
This is the single most surprising behaviour in the API, and the reason two integrations against the same endpoints can need different code.
Quote Automation is an org unit setting, and it decides who quotes the project and who moves it out of DRAFT:
| Quote Automation | What happens | What your code does |
|---|---|---|
| ON | The platform quotes the project and moves it DRAFT → PENDING by itself | Wait, re-read the status, then go to APPROVED |
| OFF | The project stays in DRAFT | Call DRAFT → PENDING yourself: that transition is what runs the quote |
With automation ON, creating work units moves the project from DRAFT straight to PENDING and calculates the cost, without you calling anything:
{
"costsStatus": "COMPLETED",
"costCalculationMode": "AUTOMATIC",
"totalCost": 78.0
}
If you then ask for that same transition yourself, it is refused, because the platform already did it:
{
"status": 422,
"code": "BWX-002",
"message": "BW Error: Unsupported transition: Pending -> Pending"
}
With automation OFF, that same call is the one doing the work, and calculateCosts: true on it is what triggers the quote:
{ "newStatus": "PENDING", "calculateCosts": true }
GET /api/v3/client/{uuid} shows which mode an org unit is in: look for sendQuoteAuto and projectAutomationEnabled.
Write code that works either way. Read GET /api/v3/project/{uuid} and branch on the actual status rather than the one you last set, send calculateCosts: true on the first DRAFT → PENDING (harmless if automation already ran), and treat Unsupported transition: X -> X as "already there", not as an error.
Learn more: How to use wxrks Quote Automation
Asynchronous operations
Anything that produces a file or recalculates a project is asynchronous, and the pattern is always the same: one call returns a job or request id, and you poll a status endpoint until it reports COMPLETED or FAILED.
| Operation | Start | Poll |
|---|---|---|
| Translated files package | POST /project/{uuid}/translation-kit-job/translated-files | GET /project/{uuid}/translation-kit-job/{jobUuid} |
| Export kit | POST .../translation-kit-job/loc-kit | same |
| Source files | POST .../translation-kit-job/source-files | same |
| Async download | POST /project/{uuid}/download | GET /project/{uuid}/download/{requestUuid}/status |
| Glossary export | GET /glossary/export/{uuid}/{fileType} | GET /glossary/export/{uuid}/{fileType}/{requestUuid}/status |
| Logfile export | GET /project/{uuid}/logfile/{uuid}/download-async | GET .../download/{requestUuid}/status |
File ingestion is the exception: it has no job id. Poll GET /api/v3/project/{uuid}/ingestion/status. It answers with just a quoted word, "COMPLETED", "COMPLETED_WARN" or "IN_PROGRESS", not an object, so strip the quotation marks before comparing.
Poll it once the work units exist. Until then it answers 200 with an empty body: the file is registered, but there is nothing yet to report on. Create the work units first and it starts reporting within seconds.
If you would rather not poll at all, register a webhook: see Stop polling, use webhooks and Webhooks.