You can set up webhooks to make Studio push data to any arbitrary external service. Webhooks can be sent for the same triggers as our other notifications channels:

  • API Error
  • Job Queued
  • Job Complete
  • Job Error

Configuration

Configuration is per-account. To set up webhooks, click Settings → Notifications → Webhook.

Enter the full URL where webhooks should be posted and enable the integration. Once set up, you can add, edit, or remove rules. The main URL will be used as the default, but you can override by specifying a different URL on a per-rule basis.

Expected Response and Retries

The webhook endpoint you provide should respond with a 200, 201, 202 or 204 response code. If we receive another response code, or the request times out after 3 seconds, we will cancel the request.

Payload Format

All payloads are delivered over HTTP/HTTPs as POSTs. Payloads can be sent in either JSON or XML format. JSON is the default; to use XML, configure that by editing each rule.

The basic payload format is:

{
  "type": "EVENT_TYPE",
  "payload": {}
}

EVENT_TYPE will be one of:

  • api_error
  • job_complete
  • job_error

The payload will vary depending on the EVENT_TYPE.

Examples

Job Complete (JSON)

{
  "accountId": 0,
  "id": 0,
  "name": "string",
  "profileId": 0,
  "state": "complete",
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "submittedAt": "2019-08-24T14:15:22Z",
  "completedAt": "2019-08-24T14:15:22Z",
  "presetType": "string",
  "type": "regular",
  "outputLog": "string",
  "expiryDate": "2019-08-24T14:15:22Z",
  "photoDownloadUrls": {
    "image_name_1": "https://<bucket_name>.s3.<region>.amazonaws.com/<file_path>?X-Amz-Algorithm=<algorithm>&X-Amz-Credential=<credential>&X-Amz-Date=<date>&X-Amz-Expires=<expires>&X-Amz-SignedHeaders=<header>&X-Amz-Signature=<signature>",
    "image_name_2": "https://<bucket_name>.s3.<region>.amazonaws.com/<file_path>?X-Amz-Algorithm=<algorithm>&X-Amz-Credential=<credential>&X-Amz-Date=<date>&X-Amz-Expires=<expires>&X-Amz-SignedHeaders=<header>&X-Amz-Signature=<signature>",
    "image_name_3": "https://<bucket_name>.s3.<region>.amazonaws.com/<file_path>?X-Amz-Algorithm=<algorithm>&X-Amz-Credential=<credential>&X-Amz-Date=<date>&X-Amz-Expires=<expires>&X-Amz-SignedHeaders=<header>&X-Amz-Signature=<signature>"
  },
  "errors": [
  	[]
  ],
    "creditAmountPerPhoto": 1.5,
    "dollarAmountPerPhoto": 2.5,
    "processed": {
    "color": 1,
    "crop": 1,
    "retouch": 1,
    "eretouch": 1,
    "extract": 1,
    "teeth": 1,
    "glare": 1,
    "glare_combo": 1,
    "braces": 1,
    "denoise": 1,
    "retouch_full_body": 1,
    "eretouch_full_body": 1,
    "total": 1
  },
    "photos": [
    {}
  ],
  "profile": {
    "id": 0,
    "accountId": 0,
    "name": "string",
    "description": "string",
    "type": "string",
    "colorRed": 0,
    "colorGreen": 0,
    "colorBlue": 0,
    "colorSaturation": 0,
    "colorContrast": 0,
    "colorHighlightContrast": 0,
    "colorShadowContrast": 0,
    "colorMidtoneContrast": 0,
    "colorDensity": 0,
    "colorGamma": 0,
    "colorPreset": "skylab",
    "cropPositionX": 0,
    "cropPositionY": 0,
    "cropScale": 0,
    "cropSizeX": 6400,
    "cropSizeY": 6400,
    "enableColor": true,
    "enableCrop": true,
    "enableGlobalColorAdjustments": true,
    "printColorParams": false,
    "printCropParams": false,
    "enable_no_image_output": false,
    "enable_strip_png_metadata": false,
    "enable_srgb_output": false,
    "createdAt": "2019-08-24T14:15:22Z",
    "updatedAt": "2019-08-24T14:15:22Z",
    "enableRetouch": false,
    "enableRetouchFullBody": false,
    "enableEnhancedRetouch": false,
    "retouchPreset": "default",
    "enableExtract": false,
    "removeSpill": false,
    "turboSpill": false,
    "replaceBackground": false,
    "dualFileOutput": false,
    "outputFileType": "png",
    "enableTeeth": false,
    "enableGlare": false,
    "enableGlareCombo": false,
    "enableBraces": false,
    "enableProof": false
	}
}

Job Error (JSON)

{
  "accountId": 0,
  "id": 0,
  "name": "string",
  "profileId": 0,
  "state": "error",
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "submittedAt": "2019-08-24T14:15:22Z",
  "completedAt": "2019-08-24T14:15:22Z",
  "presetType": "string",
  "type": "regular",
  "outputLog": "string",
  "expiryDate": "2019-08-24T14:15:22Z",
  "photoDownloadUrls": {
  },
  "errors": [
  	['Something went wrong']
  ],
    "creditAmountPerPhoto": 1.5,
    "dollarAmountPerPhoto": 2.5,
    "processed": {
    "color": 1,
    "crop": 1,
    "retouch": 1,
    "eretouch": 1,
    "extract": 1,
    "teeth": 1,
    "glare": 1,
    "glare_combo": 1,
    "braces": 1,
    "denoise": 1,
    "retouch_full_body": 1,
    "eretouch_full_body": 1,
    "total": 1
  },
    "photos": [
    {}
  ],
  "profile": {
    "id": 0,
    "accountId": 0,
    "name": "string",
    "description": "string",
    "type": "string",
    "colorRed": 0,
    "colorGreen": 0,
    "colorBlue": 0,
    "colorSaturation": 0,
    "colorContrast": 0,
    "colorHighlightContrast": 0,
    "colorShadowContrast": 0,
    "colorMidtoneContrast": 0,
    "colorDensity": 0,
    "colorGamma": 0,
    "colorPreset": "skylab",
    "cropPositionX": 0,
    "cropPositionY": 0,
    "cropScale": 0,
    "cropSizeX": 6400,
    "cropSizeY": 6400,
    "enableColor": true,
    "enableCrop": true,
    "enableGlobalColorAdjustments": true,
    "printColorParams": false,
    "printCropParams": false,
    "enable_no_image_output": false,
    "enable_strip_png_metadata": false,
    "enable_srgb_output": false,
    "createdAt": "2019-08-24T14:15:22Z",
    "updatedAt": "2019-08-24T14:15:22Z",
    "enableRetouch": false,
    "enableRetouchFullBody": false,
    "enableEnhancedRetouch": false,
    "retouchPreset": "default",
    "enableExtract": false,
    "removeSpill": false,
    "turboSpill": false,
    "replaceBackground": false,
    "dualFileOutput": false,
    "outputFileType": "png",
    "enableTeeth": false,
    "enableGlare": false,
    "enableGlareCombo": false,
    "enableBraces": false,
    "enableProof": false
	}
}

Job Queued (JSON)

{
  "accountId": 0,
  "id": 0,
  "name": "string",
  "profileId": 0,
  "state": "queued",
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "submittedAt": "2019-08-24T14:15:22Z",
  "completedAt": "2019-08-24T14:15:22Z",
  "presetType": "string",
  "type": "regular",
  "outputLog": "string",
  "expiryDate": "2019-08-24T14:15:22Z",
  "photoDownloadUrls": {
  },
  "errors": [
  	[]
  ],
    "creditAmountPerPhoto": 1.5,
    "dollarAmountPerPhoto": 2.5,
    "processed": {
    "color": 1,
    "crop": 1,
    "retouch": 1,
    "eretouch": 1,
    "extract": 1,
    "teeth": 1,
    "glare": 1,
    "glare_combo": 1,
    "braces": 1,
    "denoise": 1,
    "retouch_full_body": 1,
    "eretouch_full_body": 1,
    "total": 1
  },
    "photos": [
    {}
  ],
  "profile": {
    "id": 0,
    "accountId": 0,
    "name": "string",
    "description": "string",
    "type": "string",
    "colorRed": 0,
    "colorGreen": 0,
    "colorBlue": 0,
    "colorSaturation": 0,
    "colorContrast": 0,
    "colorHighlightContrast": 0,
    "colorShadowContrast": 0,
    "colorMidtoneContrast": 0,
    "colorDensity": 0,
    "colorGamma": 0,
    "colorPreset": "skylab",
    "cropPositionX": 0,
    "cropPositionY": 0,
    "cropScale": 0,
    "cropSizeX": 6400,
    "cropSizeY": 6400,
    "enableColor": true,
    "enableCrop": true,
    "enableGlobalColorAdjustments": true,
    "printColorParams": false,
    "printCropParams": false,
    "enable_no_image_output": false,
    "enable_strip_png_metadata": false,
    "enable_srgb_output": false,
    "createdAt": "2019-08-24T14:15:22Z",
    "updatedAt": "2019-08-24T14:15:22Z",
    "enableRetouch": false,
    "enableRetouchFullBody": false,
    "enableEnhancedRetouch": false,
    "retouchPreset": "default",
    "enableExtract": false,
    "removeSpill": false,
    "turboSpill": false,
    "replaceBackground": false,
    "dualFileOutput": false,
    "outputFileType": "png",
    "enableTeeth": false,
    "enableGlare": false,
    "enableGlareCombo": false,
    "enableBraces": false,
    "enableProof": false
	}
}

Security

In order to authenticate webhook messages from Studio, we have implemented an HMAC (HMAC (Hash-based message authentication code) within our callback PATCH request header and body.

In order to use fully utilize this feature, you will need to contact us at [email protected] to obtain a secret key for your account.

There are two authorization header keys:

X-Skylab-Signature: <signature>

X-Skylab-Timestamp: <request_timestamp>

The payload that will be used to generate the signature is <request_timestamp>:<job_json_data>.

(i.e.) Mon, 28 Aug 2023 22:58:28 GMT:{\"accountId\":6,\"id\":7612,\"name\":\"gfesheshrs\",\"profileId\":3750,\"state\":\"complete\"...}

The signature is a base 64 encoded digest of the HMAC SHA256 hash of the callback PATCH request body (in the above format) with the provided secret key.

It is your responsibility to conduct the above steps on the server side to generate a signature as per above to validate the authenticity of the signature within the authorization header in PATCH request. If you are using one of our SDKs, there will be an HMAC signature comparison function available to you.

Steps to reproduce the above signature:

  1. Get the request timestamp from the X-Skylab-Timestamp header value.
  2. Create the payload string as per the above format using the request timestamp and the callback PATCH request body joined by a : with no spaces in between.
  3. Generate an HMAC SHA256 hash of the payload string with the provided secret key.
  4. Base 64 encode the hash generated in step 4.
  5. Compare the base 64 encoded hash generated in step 5 with the signature to the X-Skylab-Signature header value in the callback PATCH request.

Compare the base 64 encoded hash generated in step 5 with the signature to the X-Skylab-Signature header value in the callback PATCH request.