This article is a good starting point if you are new to Oddjob. It explains the main concepts and the basics of working with the API. If you are already familiar with Oddjob, go straight to the documentation.
This page describes the internal Oddjob API (the Oddjob API v1 and Oddjob API v2 Swagger definitions). It is intended for RWS teams and tools only and must not be shared with third parties.
If you are an RWS partner or vendor, please use the Public API instead.
Oddjob is a localization asset management system. It stores the files received from clients together with their metadata, keeps track of every version of every file, and follows each file through the localization workflow, from import through translation and review to handback.
At its core, Oddjob works like a basic version control system:
On top of that, Oddjob connects assets to translation management systems (Phrase, formerly Memsource; Trados; and Smartling), where they are analyzed, pre-translated and translated. Oddjob.Web, the user interface at https://oddjob.moravia.com, is built on this API.
The API uses bearer tokens issued by Microsoft Entra ID (formerly Azure AD) through the client credentials flow. The request for a token is described on the Public API page. To get client credentials for an internal tool, contact the Oddjob team.
Once you have an access token, add it to the Authorization header of every HTTP request in the following format: Bearer {access_token}.
To upload a file to Oddjob, use the Files endpoint (POST /api/Files). The file must be sent as multipart/form-data. A successful upload returns a FileOid, a unique identifier that you then use in other actions: Import, Check-In and Import Meta File.
You can also upload a ZIP file containing multiple files. Each file in the archive gets its own FileOid.
Once a FileOid has been used successfully in an API action, the file is deleted from the server. Any subsequent call with the same FileOid fails with the error "The file oid does not exist on the server".
Assets are imported with POST /api/Assets, which accepts a list of assets. These are the Asset Import properties:
* Required fields that must be provided for the import.
The AssetID is generated by Oddjob, so you do not need to provide it. Import is an asynchronous operation. When it finishes, the Async response contains, for each file, the new AssetPKID, the PendingId if the file became a Pending Asset, or an error message.
Imagine you receive a file called Foo.bar and, at some point in the future, another file called Foo.bar. It is essentially the same file as before, just with some changes (linguistic or technical, such as tags). You want to make sure that you do not translate the file twice.
During import, Oddjob assigns each file an AssetID, which is the same for all versions of one file. Our Foo.bar file gets, for example, the AssetID OJ100000007, and every later version of Foo.bar gets the same AssetID. If you search for this AssetID, you get a list of all Foo.bar versions with their metadata. Versions are tracked per project and target language, so the same file imported in another language is versioned separately.
How does Oddjob know that a new file is a version of an existing one? You tell it during import through the StringAssetIdShouldBeGeneratedFrom property. Files with the same value in the same project get the same AssetID. For example, if Foo.bar always arrives in the same folder structure (e.g. Foo/Bar/Foo.bar), use that path. Another option is an external identifier from the client, such as a GUID or ID from their system that shows two files are versions of each other. If the value is itself a valid AssetID (two letters followed by nine digits, e.g. OJ100000007), it is used as the AssetID directly. If your client does not need versioning, put a random GUID into this property so that each file is treated as new.
What happens to the previous version? Only one version of a file is active at a time, as shown by the IsActive property. When a new version arrives, it normally becomes the active asset straight away. The new version becomes a Pending Asset instead, and the previous version stays active, when:
You then decide whether to wait for the previous version to be finished or to proceed with the update. Once the new version is safe to work on, call the Import Pending Asset action (GET /api/AssetsPending/{id}/Import) and it becomes the active asset. If the file arrives yet again while a Pending Asset exists, the newer file replaces the pending one.
If you need to perform an action on an asset that requires exclusive access to it, check the asset out first (GET /api/Assets/{id}/Out/{status}). The status tells others what is happening to the asset, e.g. InTranslation or BeingQAed. While an asset is checked out, nobody else can check it out.
Once you have made your changes, check the asset back in (POST /api/Assets/In). Check-in requires the uploaded target file (and, optionally, an updated source file) and the new status, e.g. Translated or HandedBack. If you decide not to make any changes, undo the check-out (GET /api/Assets/{id}/Undo), which just releases the lock.
These actions accept a comma-separated list of AssetPKIDs, so you can work with many assets in one call. The full list of statuses is in the documentation.
Some actions can take a long time to process, and your HTTP request could time out before they complete. For these actions, the API does not process the request immediately. Instead, it registers the request as an Async object and returns it to you. The request is then passed to a background service, which processes it and stores the result in the Async object.
To get the result, call the Async status endpoint (GET /api/Asyncs/{id}) with the Async ID you received. The Status property tells you whether the request is Created, InProgress or Finished. Once it is finished, the Response property contains the result as JSON. For most asset actions, this is a list of results with the AssetPKID and an error message for each asset that failed. Poll at a reasonable interval (e.g. every few seconds) rather than in a tight loop.
The following operations use the Async pattern:
If you work with a single asset, synchronous variants of Check-Out (GET /api/Assets/{id}/Out/One/{status}) and Check-In (POST /api/Assets/In/One) return the result directly.
During import, each asset is assigned a primary key called AssetPKID. With this ID, you can follow every step in the life of an asset: its history, cloud asset, meta files, tags, comments and more. The AssetPKID is also needed for all basic actions, such as check-out, check-in and undo check-out.
Every asset belongs to one specific target language. The primary language code in Oddjob is the LCID, as defined by Microsoft here. The OddjobLanguage object maps each LCID to other language code formats (e.g. ll-cc).
Sometimes you receive an asset that is not in a localizable format, such as an image or a video. In that case, you can extract the translatable text into a separate file and link it to the non-localizable parent asset. We call these files Meta Files. They are imported with POST /api/AssetsMeta. Importing a meta file for an asset overwrites the existing one.
Cloud Assets are assets that have been uploaded, in a translatable format, to a translation management system (TMS): Phrase (formerly Memsource), Trados or Smartling. A Cloud Asset can be analyzed in the TMS, which shows the effort and cost of each asset, and then pre-translated and translated. Each Cloud Asset belongs to exactly one Asset.
All API objects are available in the Oddjob.Api.Models NuGet package in the RWS package feed.