The Supertext REST API

What?

In the early days, the internet solely consisted of simple static webpages. With the Dot-Com boom (or bubble), the webpages changed into complex and dynamic applications. But they were all like islands. There was no connection whatsoever between them. But now, companies like Facebook and Twitter loosened up and enable other people to build applications, allowing to connect to them and add their own functionality.

Until now, Supertext has – besides some specific integrations – been an island too. But that’s over now. We have an open and public API allowing other applications to directly integrate with Supertext.

Why?

Who wants to integrate with Supertext you wonder? And why? Actually, lots of people. It started 4 years ago with Akero, a now defunct CMS system. Akero users were able to directly order translations and text editing from inside their CMS and got the final text delivered back into it. Clearly, this wasn’t enough to make Akero a success, but the need to order directly from 3rd party systems remained evident until today.

How?

Now it gets a bit technical. The Supertext API is built as a REST API that understands JSON or XML. Almost all modern open APIs are built alike. This means that they’re accessible with normal HTTP calls and they enable you to send and receive human readable JSON or XML messages.

We’ve created a bunch of Postman examples for you to play with. But you need to install Postman first. It’s like a beautiful version of curl to try out REST services.

https://www.getpostman.com/

Once you got Postman, you can access our REST API documentation here: https://staging.supertext.ch/api/swagger/ui/index

You can download the documentation and import it onto Postman or you can import a smaller collection directly: https://documenter.getpostman.com/view/5610/2s93Y2ThaV

More on this topic on https://remy.supertext.ch/2016/09/try-out-our-api-with-postman/

Who?

Authentication is done with OIDC and bearer tokens.

Contact us for receiving a ClientID and secret for accessing our API’s.

Where?

Please send an e-mail to remyATsupertextDOTch and I will send you the URL for the sandbox and the live system.

Language Support?

You should add Accept-Language HTTP header to all calls by default:

Accept-Language: en-US

This specifies in what language you get the results back. If you don’t specify something, the response defaults to English. Currently we support:

en-US, en-GB, fr-CH, fr-FR, de-CH, de-DE, it-CH, it-IT

Currencies

We currently support CHF, EUR and USD, depending on the Supertext office you work with. For a quote you can choose between the currencies, but if you create an order, whatever is set in your account will be used.

In the example I omitted the currency, so the currency from your account is used. Should you not be authenticated yet (for a public quoting system for example) you can just specify it like this in the root level.:

"Currency":"chf"

For the configuration

/v1/translation/languagemapping/{language}

GET – No authentication necessary.

Helps you map a language in your system to one we support.

E.g. your CMS is setup for ‘de’ (German). We don’t actually translate into German, we translate into German for Switzerland, for Germany or for Austria. So this method returns you a list of possible matches. For {language} = ‘de’ the result would look like this:

{
  "Languages":
  [
    {
      "Iso":"de-CH",
      "Name":"German (CH)"
    },
    {
      "Iso":"de-DE",
      "Name":"German (DE)"
    },
    {
      "Iso":"de-AT",
      "Name":"German (AT)"
    }
  ],
  "Supported":false
}

To get a quote

/v1/translation/quote

POST – authentication optional

Getting a quote over the API works in pretty much the same way as if you were using our normal website to order a translation (give it a try). Send us the text and in return, you see a list of possible delivery deadlines and prices per service levels  (translation/adaptation). You can send us the content structured in groups and items, which is helpful if you have CMS that is built that way. E.g. a group could be a page, items are title, content, metatags and so on. The following is a possible JSON for this call:

{
  "ContentType":"text\/html",  
  "Groups":
  [
    {
      "GroupId":"Group1",
      "Items":
      [
        {
          "Content":"This is the content of group 1",
        },
        {
          "Content":"This is more content  of group 1",
        }
      ]
    },
    {
      "GroupId":"Group2",
      "Items":
      [
        {
          "Content":"This is the content  of group 2",
          "Id":"1"
        },
        {
          "Comment":"Some info about this message",
          "Content":"This is a twitter message, that can't be longer than 140 chars.",
          "Context":"Twitter",
          "Id":"2"
          "MaxLength":"140"
        }
      ]
    }
  ],
  "Files":
  [
    {
      "ID": 17015,
      "Comment":"The main story with 585 words"
     }
   ],
  "SourceLang":"de-CH",
  "TargetLanguages":["de-ch", "ru"],
}

For the quote you don’t need to specify fields like Id, Context, etc. Only the Content field is important and only the Content filed will be counted.

If you don’t have the content yet, or if you already know the word count you can alternatively specify the WordCount field. It takes precedence over the content in the Groups collection. If you use your own word count the final price might be a bit different, since we will eventually count the content our self and use that count to calculate the final price.

{
  "ContentType":"text\/html",
  "Currency":"chf",
  "SourceLang":"de-CH",
  "TargetLanguages":["de-ch", "ru"],
  "WordCount": 235
}

And this could be what you get in return:

{
  "Currency":"CHF",
  "WordCount": 123,
  "Options":
  [
    {
      "DeliveryOptions":
      [
        {
          "DeliveryDate":"2012-02-22T09:25:46.0000000Z",
          "DeliveryId":1,
          "Name":"6h",
          "Price":124
        },
        {
          "DeliveryDate":"2012-02-22T15:25:46.0000000Z0",
          "DeliveryId":2,
          "Name":"24h",
          "Price":110
        },
        {
          "DeliveryDate":"2012-02-23T15:25:46.0000000Z",
          "DeliveryId":3,
          "Name":"48h",
          "Price":96
        },
        {
          "DeliveryDate":"2012-02-24T15:25:46.0000000Z",
          "DeliveryId":4,
          "Name":"3 Days",
          "Price":82
        },
        {
          "DeliveryDate":"2012-02-28T15:25:46.0000000Z",
          "DeliveryId":5,
          "Name":"1 Week",
          "Price":69
        }
      ],
      "Description":"Professional translation with a review by a second translator (two-phase service). We use machine translation solutions as a basis for our work where appropriate. You receive a natural-sounding, flawlessly accurate text. Polished and precise.",
      "Name":"Translation",
      "OrderTypeConfigurationId":187,      
      "OrderTypeId":61,
      "ShortDescription":"For general texts with minimal specialist terminology"
    },
    {
      "DeliveryOptions":
      [
        {
          "DeliveryDate":"2012-02-22T15:25:46.0000000Z",
          "DeliveryId":2,
          "Name":"24h",
          "Price":254
        },
        {
          "DeliveryDate":"2012-02-23T15:25:46.0000000Z",
          "DeliveryId":3,
          "Name":"48h",
          "Price":222
        },
        {
          "DeliveryDate":"2012-02-24T15:25:46.0000000Z",
          "DeliveryId":4,
          "Name":"3 Days",
          "Price":190
        },
        {
          "DeliveryDate":"2012-02-28T15:25:46.0000000Z",
          "DeliveryId":5,
          "Name":"1 Week",
          "Price":159
        }
      ],
      "Description":"Professional translation with a review by a second translator (two-phase service). You receive a natural-sounding, flawlessly accurate text. Polished and precise.",
      "Name":"Adaptation",
      "OrderTypeConfigurationId":7,
      "OrderTypeId":7,
      "ShortDescription":"For particularly important texts requiring a complete cultural reworking"
    }
  ]
}

In the above example, no OrderTypeConfigurationId or ServiceTypeId was specified. In this case the Translation service-type (46) will be used as a default and the results specify a selection of translation options.

Here are some points to help you determine which …TypeId to send:

  • You can only specify a ServiceTypeId or an OrderTypeConfigurationId, but not both.
  • If you want to see the general, public order-types, then specify the ServiceTypeId (see the table below for the corresponding values).
  • If you believe you have an agreement with Supertext then this probably means that you have a specific OrderTypeConfigurationId. If you don’t already know this, contact your Project Manager and ask.

Possible ServiceTypeId and OrderTypeConfigurationId values:

ServiceTypeId Service
1 Text Tuning Services
OrderTypeConfigurationId Order type
1 Total Revision
2 Fine-tuning
2 Creation
OrderTypeConfigurationId Order type
3 Copywriting
4 Creation Trio (Only on request)
3 Proofreading Service
OrderTypeConfigurationId Order type
5 Proofreading
10 Proofreading (two-phase service)
46 Translation Services
OrderTypeConfigurationId Order type
187 Translation

Service-types can be thought of as the top-level grouping of our available services, whereas order-types are the specific instances. For example, we offer translation services, but translation alone doesn’t specify how the work will be done (i.e., will machine translation be involved? Will it be proofread by a different translator? Does it require specialist knowledge?).

Order-type configurations can be thought of as customised versions of an order-type (the customisations can involve, for example, the workflow, pricing, etc.).

Therefore, if you know the specific OrderTypeConfigurationId that you want, you should specify this. Alternatively, specify the ServiceTypeId and we’ll show you some options. However, if you do know which order-type you want (and don’t need to see the options) then specify the ServiceTypeId and the OrderTypeId and you will receive only the price/delivery options for that type.

To display the order-type options, we suggest you use something like this:

Use a nested list with the order types and then the deadline options inside them.

Create an order with content inside the JSON

v1.1/translation/order

POST – authentication necessary

When making an order, we need more details than we need for a quote. At first, we need to know which quote you’ve chosen. So you have to add the OrderTypeConfigurationId and the DeliveryId.

Very important is the CallbackUrl. After the translation job is finished, we will call this URL with a similar JSON order object and write back the translated content into your system.

We strongly advise you to use the following fields:

OrderName: Some short description about this order. E.g. “Spring sale”

ReferenceData: Anything you need to identify this order later (besides the GroupId and the Id for the Content field). And optionally, you could add some security token so that not everybody with access to the callback URL can update your system.

Referrer: Name of your website or system. E.g. Supertext US Website

{
  "CallbackUrl":"http://localhost:65346/API/ApiCallbackExample.aspx",
  "ContentType":"text\/html",
  "DeliveryId":1,
  "OrderName":"Some title",  
  "AdditionalInformation":"Please make sure you always translate this like that.",
  "OrderTypeConfigurationId":187,
  "ReferenceData":"NodeId:4ee69461-1c8d-4fbe-9d77-7d05e46bc4a8",
  "Referrer":"WordPress Supertext Plugin",
  "SystemName":"Supertext Blog",
  "SystemVersion":"4.6",
  "ComponentName":"polylang-supertext",
  "ComponentVersion":"2.4",
  "SourceLang":"de-CH",
  "TargetLanguages":["fr-CH", "en-US"],
  "Groups":
  [
    {
      "Context":"Some Node",
      "GroupId":"Group1",
      "Items":
      [
        {
          "Comment":null,
          "Content":"This is the content of group 1",
          "Context":null,
          "Id":"1"
        },
        {
          "Comment":null,
          "Content":"This is new content of group 1",
          "Context":null,
          "Id":"2"
        }
      ]
    },
    {
      "Context":"Some other Node",
      "GroupId":"Group2",
      "Items":
      [
        {
          "Comment":null,
          "Content":"This is the content of group 2",
          "Context":null,
          "Id":"1"
        },
        {
          "Comment":"Some info about this message",
          "Content":"This is a twitter message, that can't be longer than 140 chars.",
          "Context":"Twitter",
          "Id":"2"
          "MaxLength":"140"
        }
      ]
    }
  ]
}

Comment, Context, MaxLength are optional. The Id is important so that you will know where to write this item back into your system. We don’t guarantee the sequence. MaxLength is helpful for things like Twitter Messages or fixed length fields, so that we don’t translate this item with too many characters.

You get back another order object with the order Id, a price, order and delivery date. All the other data is just for your reference.

{
  "Id":12023,
  "OrderDate":"2012-02-09T13:43:46.0000000Z",
  "Deadline":"2012-02-09T13:43:46.0000000Z",
  "Price":199,
  "Currency":"chf",
  "DeliveryId":1,
  "OrderTitle":"Some title",
  "OrderTypeConfigurationId":187,
  "OrderTypeId":61,
  "ReferenceData":"NodeId:4ee69461-1c8d-4fbe-9d77-7d05e46bc4a8",
  "SourceLang":"de-CH",
  "TargetLang":"en-US",
  "Status":"New"
}

Below a workflow graph on how the whole process works if you supply the content inside the order or quote JSON REST call.

Create an order with content that’s inside a file

Assuming you don’t have the translatable text in some type of file format that you can’t easily extract or you would loose valuable layout information if doing so, you can send us files directly (Examples are Word, InDesign, etc.). The basics are exactly the same as with the call above, but instead of Groups of Content you just send us the files first and then create the order in a second step.

v1/files

POST – Authentication necessary

This, unlike the other calls is a multiplart form-data post. And we need the following form elements:

ElementId = 0
ElementTypeId = 2
DocumentTypeId = 1

And obviously you have to attach the file.

Depending on the client framework you are using, I should not set the Content-Type, more info on http://stackoverflow.com/questions/19178813/sending-multipart-mixed-content-with-postman-chrome-extension.

The response you get should look something like that:

[
 {
 "Comment": "",
 "CreationDate": "2016-09-23T08:16:35+00:00",
 "LastUpdated": "2016-09-23T08:16:35+00:00",
 "UploadedById": 381,
 "UploadedByName": "Hans Muster",
 "WordCount": 109,
 "Type": "Original",
 "IsEditable": false,
 "IsTemplate": false,
 "ContentType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
 "ElementId": 0,
 "ElementTypeId": 2,
 "Id": 380995,
 "Name": "Example_109_Words.docx",
 "Size": 11935,
 "TypeId": 1
 }
]

But the only thing you really need is the Id (in this case 380995). You’ll need this Id to create the order now.

The basics are exactly the same like the order call above, but instead of Groups of Content you just add the file Id.

v1.1/translation/order

POST – authentication necessary

As you can see in the example below, the Files section replaces the Groups section. You can also combine them if you want. For example to add supporting documents or images.

{
  "CallbackUrl":"http://localhost:65346/API/ApiCallbackExample.aspx",
  "DeliveryId":1,
  "OrderName":"Some title",  
  "AdditionalInformation":"Terminology is important.",
  "OrderTypeConfigurationId":187,
  "ReferenceData":"NodeId:4ee69461-1c8d-4fbe-9d77-7d05e46bc4a8",
  "Referrer":"WordPress Supertext Plugin",
  "SystemName":"Supertext Blog",
  "SystemVersion":"4.6",
  "ComponentName":"polylang-supertext",
  "ComponentVersion":"2.4",
  "SourceLang":"de-CH",
  "TargetLanguages":["en-US", "fr-FR"],
  "Files":
  [
    {
      "ID": 17015,
      "Comment":"The main story with 585 words"
     }
   ]
}

And adjusted workflow if you supply your content inside one or multiple files:

Status

/v1/order/{id}

GET – authentication necessary

In order to track the status of an order, just use the Id you got after you submitted the order. You will get an Order object like the one above as a return.

Callback

In order to get your translation back from us, you need to provide us with a callback URL.
When you create the order, you have to use the field CallbackUrl. This URL needs to accept a JSON of the type Order (as shown above). That Order object will contain your translation in the Groups and Item fields with the same Id’s, so you can map them back to your own datastructure.
We recommend that you use the ReferenceData field as some type of authentication. For example you could use a combination of an internal Id and the MD5 hash of this Id. We will return the ReferenceData field in our callback. You can then just check if the Hash matches to make sure nobody else is writing into your system.

Callback from an order with content that’s inside a file

After you receive our callback, you can get the complete order object with all associated files like this:

/v1/order/{id}

id is the order ID that you initially got. But it’s also in the callback.

The result should look something like that (simplified object):

{
    "AdditionalInformation": null,
    "Amount": 802,
    "Deadline": "2018-07-05T11:45:00.0000000+00:00",
    "DeliveredDate": null,
    "DeliveryId": 4,
    "Files": [
        {
            "DocumentType": "Final",
            "ContentType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "DocumentTypeId": 2,
            "ElementId": 152457,
            "ElementTypeId": 2,
            "Id": 1987285,
            "Name": "Services-Workflow-and-Technology.docx",
            "Size": 13470,

        },
        {
            "DocumentType": "Source",
            "ContentType": "image/png",
            "DocumentTypeId": 3,
            "ElementId": 152457,
            "ElementTypeId": 2,
            "Id": 1987268,
            "Name": "OrderProcess_Files.png",
            "Size": 140689,
        }
    ],
    "Groups": null,
    "Id": 152457,
    "SecurityLevelId": null,
    "ServiceType": "translation",
    "ServiceTypeBaseId": 3,
    "ServiceTypeId": 46,
}

Important is the Files collection. Look there for files with the DocumentType = “Final” or DocumentTypeId = 2 (both refer to the same state). These are the translated files. There can be one or multiple, depends on how many you sent originally.

Then you can download the files from this link:

https://staging.supertext.ch/FileDownloads/File/1987285/Services-Workflow-and-Technology.docx
Replace 1987285 with the ID from the file collection and do the same for the filename.

Return value for the callback

Usually you return a 200 OK to our callback. Or a 500 for an error. A good error description in the content helps.

200 means our callback was successfully processed on your side and the translations have been applied to the pages. All is done and (potentially) only needs the users approval to be published. Internally our order is set to the status “Delivered” and “Collected”.

If this process runs in multiple steps and maybe can’t be finished during the callback, then please return a 202 ACCEPTED instead. The order is then only set to “Delivered” in our TMS.

Later when the import process is finished on your side, call the status API to update the order status to “Collected”:

/v1/order/status/{id}/9

PUT – authentication necessary

9 is the StatusId and means “Collected”. Please don’t ignore this workflow approach. This is very important for our Project Managers and for our customers so that we know the real status of the writeback and can react quickly if something is not happing in the right way.

Dates

All dates are in UTC and in the ISO_8601 format:

2012-05-03T12:09:46.0000000Z

If you are using .NET just use Convert.ToDateTime(), this will automatically convert from the UTC time to your local time.

Building your own integrations

A few things to remember:
1. Implement a bulk order mode. Most integrations initially only allow to order individual pages or items. But that usually is not feasibly for larger projects.
2. Handle the case where the client changes or deletes the original item, before we can write back the translation. The easiest thing is to block any changes in the original item.




Ähnliche Beiträge


8 Kommentare zu “The Supertext REST API”

Leave a Reply

Your email address will not be published. Required fields are marked *



*