Listeners (Preview)
Listeners allow a connector to be notified on events of interests, commonly referred to as webhooks. These are HTTP callbacks that the API sends, via POST method, to a URL that the application configures.

Usage

Assuming your connector can listen to webhooks at URL: https://provider-connector/callback. Create a listener on the API:

Method: POST ​/listeners​

With the following request body:

{
  "jobUri": "https://provider-connector/callback",
  "jobStatusCodes": [
    "SENDING_READY_FOR_RETRIEVE"
  ]
}

This creates a global listener that generates events on jobs that are submitted by ContentAPI users, for all providers created by the provider connector. Here is a sample callback:

{
  "providerId": "u6QpOENThlh26P",
  "jobId": "SBXT8hZS",
  "eventType": "JOB_UPDATE",
  "updateTime": "2021-09-20T14:40:26.178Z",
  "statusCode": "SENDING_READY_FOR_RETRIEVE"
}

For more information on the different types of listeners that can be created, as well as details on various fields on the callback object, please refer to the API specification.

Optional: Signature Validation

When a listener is created with the LB_PROVIDERAPI_SIGNATURE auth type, which is the default, a signature will be included in the callback request header x-lionbridge-providerapi-signature. This can be used to validate the payload sender is Lionbridge.

To validate a request:

  1. Create a hash with the auth secret when creating the listener, along with the payload
  2. Compare created hash with the signature header value.

The hash is generated using a hash-based message authentication code (HMAC) with SHA-256. For sample code, please visit this page.

Here is an example with Java, where secret is the auth secret, and Message is the payload JSON message body.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class ApiSecurityExample {
  public static void main(String[] args) {
    try {
     String secret = "secret";
     String message = "Message";

     Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
     SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
     sha256_HMAC.init(secret_key);

     String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
     System.out.println(hash);
    }
    catch (Exception e){
     System.out.println("Error");
    }
   }
}

Events

Below are some events that may be relevant. Refer to the API specification for up-to-date information on available events and callback payload format.

New job submission

Create a listener, specifying the jobUri and include SENDING_READY_FOR_RETRIEVE in the jobStatusCodes field:

{
  "jobUri": "https://provider-connector/callback",
  "jobStatusCodes": [
    "SENDING_READY_FOR_RETRIEVE"
  ]
}

Here is a sample callback:

{
  "providerId": "u6QpOENThlh26P",
  "jobId": "SBXT8hZS",
  "eventType": "JOB_UPDATE",
  "updateTime": "2021-09-20T14:40:26.178Z",
  "statusCode": "SENDING_READY_FOR_RETRIEVE"
}

Job archival and deletion

Job deletion and archival events are implicitly included when jobUri is defined on a listener. They are always triggered regardless of the jobStatusCodes values of a listener. Here is a sample callback:

{
  "providerId": "u6QpOENThlh26P",
  "jobId": "SBXT8hZS",
  "eventType": "JOB_UPDATE",
  "updateTime": "2021-09-20T14:49:03.284Z",
  "statusCode": "COMPLETED",
  "archived": true,
  "deleted": false
}

Asset task Rejection

TODO

Asset task Approval

TODO

Best Practice

Return 200 quickly

The recommended approach for integration is to always accept the callback upon receipt. A typical approach would be to:

  1. Accept the payload and immediately return HTTP 200 OK.
  2. Perform business logic as necessary,
  3. Or discard the event.

The endpoint may receive many requests depending on activities on the API. Consider separating the event ingestion in Step 1 and asynchronosly perform business logic in Step 2.

Error handling and Retries

The user-specified endpoint is expected to return 200 on success. If the callback delivery fails, the API retries for up to 24 hours with an exponential backoff.

Ordering

Due to the nature of webhook delivery, events are not guaranteed to be in order. For example, a job was first set to COMPLETE status and subsequently archived. Suppose the endpoint was not available when the COMPLETE webhook was sent, but recovered when the job was archived. The archived webhook would arrived first, then later the COMPLETE webhook on the next retry. Ensure the integration can handle out-of-order events gracefully.

Tools

The same approach outlined on Testing can be used to generate test events for listeners. In addition, here are some tools that can help during the development phase:

  1. webhook.site This site can be used as a test endpoint for inspecting the webhook payload.

  2. ngrok This tool can be used to expose an endpoint on a development environment for the API to reach.