Handling Asynchronous APIs with Webhooks

The Image Intelligence API is asynchronous. This usually means POST requests that involve batch processing won't give a result immediately. To deal with this, most endpoints accept an optional webhookUrl. We use the webhookUrl to send results back to you when a job is complete. For example in your request payload:

{
  "webhookUrl": "https://mycompany.com/webhooks/image-intelligence"
}

Below is an example webhook response from a /detect request:

{
  "id": "5d689c71-e68f-46c3-ac71-4053806e71de",
  "jobResults": [
    {
      "class": "person",
      "image": {
        "id": "52547074-a622-11e6-8f61-63f37dc33285",
        "url": "https://publicly.available.domain.net/image-001.jpg",
        "proxyUrl": "https://api.quickpix.io/images/c7e9a2ca-c2ee-4290-90b4-04fe3df35be0",
        "customId": "some_person_filled_image",
        "confidence": 0.9971387386
      },
      "hitl": true
    },
    {
      "class": "car",
      "image": {
        "id": "52547074-a622-11e6-8f61-63f37dc33286",
        "url": "https://publicly.available.domain.net/image-002.jpg",
        "proxyUrl": "https://api.quickpix.io/images/c7e9a2ca-c2ee-4290-90b4-04fe3df35be1",
        "customId": "some_car_filled_image",
        "confidence": 0.9987652302
      },
      "hitl": false
    }
  ],
  "imageResults": [
    {
      "id": "52547074-a622-11e6-8f61-63f37dc33285",
      "url": "https://publicly.available.domain.net/image-001.jpg",
      "proxyUrl": "https://api.quickpix.io/images/c7e9a2ca-c2ee-4290-90b4-04fe3df35be0",
      "customId": "some_person_filled_image",
      "objects": [
        {
          "class": "person",
          "confidence": 0.9971387386,
          "verdict": true
        }
      ],
      "status": "COMPLETED_SUCCESSFULLY"
    },
    {
      "id": "52547074-a622-11e6-8f61-63f37dc33286",
      "url": "https://publicly.available.domain.net/image-002.jpg",
      "proxyUrl": "https://api.quickpix.io/images/c7e9a2ca-c2ee-4290-90b4-04fe3df35be1",
      "customId": "some_car_filled_image",
      "objects": [
        {
          "class": "car",
          "confidence": 0.9987652302,
          "verdict": true
        }
      ],
      "status": "COMPLETED_SUCCESSFULLY"
    }
  ],
  "createdAt": 1487648348000,
  "status": "COMPLETED_SUCCESSFULLY",
  "customId": "6c78df0a-67b6-4d5f-93cf-5820cfee501c",
  "feedId": "Camera_123456",
  "webhookUrl": "https://publicly.available.domain.net/90f8754aa4e287bbb2c07ec99ade0de72ddbd4b6Et"
}

Considerations

There are a few nuances to consider when dealing with webhooks. These should be taken into account when trying to deal with error cases.

  1. Webhooks are only triggered when the entire job is complete.

    We don't support lower granularity levels. If you'd like to know when an individual image has completed you could either send a request with a batch_size of 1 or poll for the result (see alternatives below for details).

  2. The webhookUrl you provide must be a public endpoint.

    We do not support webhook URLs that sit behind authentication. The webhookUrl must be a public-facing HTTP endpoint supporting POST requests.

  3. Your webhook service must respond within 10 seconds.

    We wait 10 seconds before we timeout and drop the request. After a while, we will retry the same request.

  4. Webhooks must return a success response (we retry).

    When a non 200 status code is returned from your webhookUrl, we retry up to 5 times before giving up.

Alternatives

If your service does not have a public-facing HTTP interface, you can avoid using webhooks entirely. Our API provides /detect/{id} and /match/{id} endpoints allowing you poll for results.

The response from POST to the /detect or /match endpoints return an id representing the job. From there you can query the job for its completion status e.g. GET /detect/f9d73f87-25bc-4d21-bc72-c15949ed1d26.