Update: Apr 16, 2026
Viomba Dekaani is an API to access Viomba's core services programmatically. In order to use the API, please, contact Viomba to get yourself an account.
Viomba services are based on Viomba's proprietary AI models. The models have been trained with samples collected from actual consumers equipped with high-precision eye tracking devices connected to their browsers.
"Dekaani" is Finnish and translates "Dean" in English. The name was chosen for the process controlling the task flow to the worker nodes which are called "Professori"s = "Professor" in English.
The API is available over HTTPS and it uses JSON-encoded messages in HTTP body to exchange information. All the requests require authentication and are available for authorized accounts, only.
Each account is assigned a set of task types that it is permitted to use. Requests to task types not assigned to the account will be rejected with 403 Forbidden. The available task types for an account are managed by Viomba.
Internal accounts used by Viomba are exempt from task type restrictions and may submit any task type.
All API operations start by the client calling one of the API end-points. There are two different ways how the client can get the result back from the server:
Both ways are available to all the requests at the same time. Even if the client uses a webhook, it can also poll for the result for the same request.
Once client has sent a request to the API, the API assigns a task_id for the task and returns it to the client.
The client can start checking for the result by calling POST /api/result/{task_id} with the task_id.
The result end-point will respond with either
task_id is not found, or it does not belong to the same account. This status is final.In case of "error" status, the end-point provides a description for the error.
In case of "success" status, the end-point provides the result data.
Completed tasks will be available for at least a week.
If the client wants the server send the results back using a webhook, it can do so by adding the callback URLs in the request. The client needs to state two webhook URLs:
successUrl which will be used by the server to send the result if the request was successfully completed by the server, anderrorUrlwhich will be used if errors occurred during the handlingThe webhook process flow is:
task_id which is returned to the clienttask_idtask_idOnce the server has completed the request, it will either call the "successUrl" or "errorUrl" given in the request, depending on if the request was processed successfully or not. When calling back, the server will include the response data (when calling successUrl), and any passThrough data from the request.
When ever a client calls the API, or the server calls back the client, the request / response data is wrapped in a message container, which is sent using http "POST" method to the other party:
{
data: <string, the payload of the request object serialized as a string>,
created: <numeric, the unix time when the request was generated; Mind that the value is milliseconds!>,
key_id: <numeric, the identifier of the key used for the MAC calculation>,
mac: <string, MAC for authentication>
}
The properties of the data object varies between the API end-points.
All the requests to the API needs to be authenticated with a message authentication code (MAC). The MAC is a SHA256-digest calculated from a string containing
<data><created><key_id><ssk>
where
and included in the message from which it was constructed.
When the server calls back the client, it will also sign the payload of the response. It is recommended that the client checks that the MAC in the response is correct to ensure authenticity of the response.
The data might be omitted and treated as an empty string whenever an endpoint doesn't require it.
If you wish to, instead of providing created, key_id and ssk in the message body, you can set the following headers in the request:
You will still need to provide the data object data as a JSON encoded string if required by the endpoint.
Given the following data...
{
"passThrough": {
"data": "xyz"
},
"errorUrl": "https://client.com/api?result=error",
"successUrl": "https://client.com/api?result=success"
}
...and a key id and shared secret...
"key_id": 3,
"ssk": "4ba05045a317c3e8d70562b9e9a8fc62db3a580551cbcc682daf33891d955f27"
...a correctly signed request would look like this
{
"data": "{\"passThrough\":{\"data\":\"xyz\"},\"errorUrl\":\"https://client.com/api?result=error\",\"successUrl\":\"https://client.com/api?result=success\"}",
"key_id": 3,
"created": 1739261442176,
"mac": "21bde916eb5565dfa729b55da916ea4abd2699050515533b75c743072cc4aecd"
}
The API imposes rate limits for the clients. If any of the rate limits are met, when the client calls the API, the API will respond with an error message, and the client needs to re-send the request later.
There are 2 limits for each account: The maximum number of request per minute, and per hour.
The benchmark endpoint has a separate general rate limit.
NOTE: Rate limiting is not applied to api/result end-point.
If the client uses end-points which upload result files to S3 bucket, the client needs to deliver its S3 settings to Viomba. The same S3 settings will be used by the API for uploading the result files.
The settings consists of
The default bucket can be changed by the client for each request, if needed.
When the server has completed a request, it will call either the successUrl or errorUrl of the request. The body of the call is a JSON-encoded object with the task_id that was handed to the client when the request was accepted, together with the possible result data from the end-point.
The server expects the client callback URL to respond with a status code 2xx. If the status code is not 2xx, it is assumed that the delivery failed, and the server will retry later up to 3 times.
The server callback is signed the account ssk. If there are more than one ssks for the account, the one used by the server can be identified by the key id.
{
"data": "{\"task_id\":1759,\"passThrough\":{\"customer_data\":\"xyz\"}}",
"created": 1739266858157,
"key_id": 5,
"mac": "6e517b90b551557eff2809d9c9c4a5945c1912aa77ccfe3098dbac6aaba1a507"
}
All end-points except api/result and api/benchmark have certain standard request parameters in the data-object:
data: {
successUrl: <string, callback URL for successful response. Optional - if not set, client must call api/result to get the result data>.
errorUrl: <string, callback URL for failed response. Optional - if not set, client must call api/result to get the result data>,
passThrough: <string, optional, data the client wants to pass back to itself>,
s3Config: <object, optional, alternative upload S3 settings to use>
}
s3Config-object, if present, is defined as:
{
region: <string, name of the AWS region>,
bucket: <string, name of the bucket>,
accessKeyId: <string, AWS accessKeyId>,
secrectAccessKey: <string, AWS secretAccessKey>
}
An example of a complete request to the ad_slicer end-point is below:
POST https://dekaani.viomba.com/api/ad_slicer
{
"data": "{\"pageUrl\":\"https:\\\/\\\/adserver.com\\\/ad\\\/12345\\\/\",\"successUrl\":\"https:\\\/\\\/myapp.com\\\/result\\\/success\",\"errorUrl\":\"https:\\\/\\\/myapp.com\\\/result\\\/error\",\"passThrough\":\"{'mydata':'myvalue'}\"}",
"created": 1739434653000,
"key_id": 1,
"mac": "0a52c552b3ae8314e401403a2dbb8bf18f8428fe9db445c1f801286cdf877714"
}
The API always responds with the same response with the task ID the server has assigned to the request, if successful:
{
success: true,
task_id: <numeric, the ID assigned to the request by the server>,
message: 'task queued with the id xxxx'
}
or if the request was not accepted, with an error:
{
success: false,
message: <string, the description of why the request could not be accepted>
}
Possible protocol level errors
If the request is accepted it's still possible for the request processing to fail for various reasons. In this case the provided error URL will be called with the reason after Viomba Dekaani has finished processing the request.
{
error: "Error while processing task: data should have required property 'pageUrl'",
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Once client has sent a request to any of the other end-points, it can call this end-point to check for the results. The referenced task is given as an URL parameter.
Required parameters (path):
task_id (number) the task for which the result is being checked.Response object:
status (string) either processing, error or successdata (object) optional, present when status is error or success. For errors, contains an error field describing the issue. For successes, contains the response payload. The object contents depend on the end-point which handled the task. See the different response objects in the end-point descriptions later.If the request is invalid, the end-point will respond with an appropriate HTTP status code (500, 429, 404, 403, 401 or 400). The response body might contain optional information, but no status is provided.
The mac for this request should be computed from the string <task_id><created><key_id><ssk>
Note that when querying results the task id needs to be appended to the mac hash string even though it's not part of the request body!
{
key_id: 4,
created: 1741073863624,
mac: '7af63913b381a6410d1ce6435fc2254558d9957819358b3ae0de9b3f7883bd5b'
}
{
status: 'processing'
}
Task success response
{
status: 'success',
data: { task_id: 1234, passThrough: { customer_data: 'xyz' } }
}
Task error response
{
status: 'error',
data: {
error: "Error while processing task: data should have required property 'urls'",
task_id: 1234,
passThrough: { customer_data: 'xyz' }
}
}
Uploads a file to the account's configured S3 bucket and returns the public URL. This is a convenience endpoint that allows clients to upload files (such as images or videos) directly, instead of having to host the files themselves and provide a URL. The returned URL can then be used in subsequent task requests that require file URLs as input.
This endpoint accepts the raw file binary as the request body (not JSON) and uses header-based authentication exclusively.
The maximum upload size is 200 MB by default.
The upload endpoint uses the following HTTP headers for authentication:
upload<created><key_id><ssk>Note the fixed string upload is used as the data component of the MAC, since the binary body is not included in the hash.
POST /api/upload
Content-Type: image/png
x-auth-key: 3
x-auth-created: 1739261442176
x-auth-mac: a8f2e1d3b4c5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0
<binary file data>
{
success: true,
url: 'https://customer-bucket.s3.us-east-1.amazonaws.com/dekaani/5/a1b2c3d4-e5f6-7890-abcd-ef1234567890',
key: 'dekaani/5/a1b2c3d4-e5f6-7890-abcd-ef1234567890'
}
Response object properties:
success (boolean) true if the upload was successfulurl (string) the public URL of the uploaded file, ready to use in task request parameterskey (string) the S3 object key of the uploaded file401 Authentication failed — missing or invalid authentication headers400 No file transfer configuration — the account has no S3 settings configured400 Missing or empty file data — no body was provided in the request429 Rate limit exceeded — the upload counts against the same per-account rate limits as task submissionsNOTE: Files uploaded through this endpoint are stored in the account's S3 bucket under the dekaani/ prefix. These files are not automatically deleted. The client is responsible for cleaning up uploaded files that are no longer needed.
A test end-point for developers. The end-point has no required parameters, as it is intended for the developers to test the authentication.
{
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Slices an ad into PNGs and stores them into a S3 bucket. The ad must be available over HTTPS, like on an ad server, or a document hosted on a web server.
Required parameters (exactly one of the following):
pageUrl (string) a URL pointing to a full HTML document (including HTML and BODY tags) displaying the ad. Must be omitted if htmlTag is provided.htmlTag (string) the HTML tag for the ad. Must be omitted if pageUrl is provided.Optional parameters:
bucketName (string) name of the S3 bucket where the images are uploaded, if different from the default bucket of the accountxand y CSS pixel offset from the top left corner of the document, if the ad is not located at (0,0)width and height CSS pixel dimensions of the creative. These must be given, if the creative does not have clear size, but dynamically adjusts itself to the viewport.locale the language tag which the browser will send in the Accept-Language header when retrieving the ad. The default value is en-USResponse object properties:
slices (array of objects) list of images (at least 1) where each screen shot image is an object containing properties
t (number) time stamp, number of milliseconds from the start of the animationurl (string) URL of the imagewidth (number) the pixel width of the imageheight (number) the pixel height of the imagehash (string) perceptual hash value for the sliced image(s), for example 0xedfa4b8e164e14e8. The hamming distance between two perceptual hashes can be used to estimate the similarity between two inputs.{
slices: [
{
t: 0,
url: 'https://customer-bucket.s3.amazonaws.com/1207987adffbebe418124812409880909abbcdeee890109824124214bbfaasf.png',
width: 300,
height: 300
}, {
t: 200,
url: 'https://customer-bucket.s3.amazonaws.com/b59beafc59fea5c95abe899b58aeb48ce4bcef4b4b4489bba494e4bac498333.png',
width: 300,
height: 300
},
],
hash: '0x930b70141ffd1374',
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
The creative_prediction, heatmap_prediction and focus_prediction endpoints accept data URLs in place of regular URLs for the image or video input. This allows sending file data inline without hosting it separately.
Caveats:
Predicts the performance of the creative from one (or multiple, if animated) image(s) of the creative.
Required parameters:
urls (array of strings) URLs of the creative image(s) to be predicted. In case of an animated ad, the images are taken in different stages of the animation, and given in the same order as in the animation. Data URLs (data:image/...;base64,...) are also accepted.model_type (string) the AI model version that should be used for the prediction. Each model version is trained with a different training data. The options are:
mobile_display and desktop_display are used with the images of the creative alone, without any parts of the surrounding site;mobile_display_context and desktop_display_context are used with images of the whole web page where the creative is present. The creative is highlighed with alpha-channel in the image(s).Response object properties:
modelVersionNumber (numeric) the version number of the Viomba's AI model usedseen (numeric) predicted share of the impressions which will be viewed by the consumers for at least 200ms.seen3000 (numeric) same as seen but at least 3000ms.seen6500 (numeric) same as seen but at least 6500ms.seen8500 (numeric) same as seen but at least 8500ms.viewtime (numeric) predicted average viewing time of the ad among those consumers who have viewed it at least 200ms. The unit is milliseconds{
modelVersionNumber: 112,
seen: 0.07857066988945008,
seen3000: 0.02052544504404068,
seen6500: 0.006649241596460342,
seen8500: 0.0050738144665956495,
viewtime: 9772,
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Predicts the distribution of the focus points of viewing on different areas of a display ad surface. The ad creative is given as one (or multiple, if animated) image(s).
Required parameters:
urls (array of strings) URLs of the creative image(s) to be predicted. In case of an animated ad, the images are taken in different stages of the animation, and given in the same order as in the animation. Data URLs (data:image/...;base64,...) are also accepted.label (string) the type of the heatmap in terms of milliseconds from the start of the viewing. The options are
all all the viewings0e50 viewing that takes place during the first 50 milliseconds of viewings50e200 viewing that takes place during 50 - 200 milliseconds from the start of viewings200viewing that takes place after the first 200 milliseconds from the start of viewingtarget (string) the device type where the viewing is supposed to take place. The supported values are mobile and desktopOptional parameters:
bucketName (string) name of the S3 bucket where the images are uploaded, if different from the default bucket of the accountblackPoint (number) the black point for contrast adjustment. The value must be between 0 and 1 and less that the whitePoint. The default value is 0.whitePoint (number) the white point for contracts adjustment. The value must be between 0 and 1 and greater than the blackPoint. The default value is 1.Response object properties:
heatmap (string) the public URL of the heatmap (gray scale)colored (string) the public URL of the heatmap, colored versionfogmap (string) the public URL of the fog map (inverted heatmap)modelVersionNumber (numeric) the version number of the Viomba's AI model used{
heatmap: 'https://customer-bucket.s3.amazonaws.com/9085481309abbd57abbd1358abbdef.png',
colored: 'https://customer-bucket.s3.amazonaws.com/addf8b4684rer8466ae88cd8abgd23.png',
fogmap: 'https://customer-bucket.s3.amazonaws.com/6814e86d86bb888fffa687c6e9a7e9.png',
modelVersionNumber: 106,
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Renders Facebook ad previews into timed PNG slices and stores them into a S3 bucket. Each preview URL is loaded in a browser, and the ad is captured at regular intervals during its animation.
The preview URLs are obtained from the Facebook Marketing API's Ad Previews endpoint (/generatepreviews). That endpoint returns an iframe-based ad preview; the src attribute of the returned iframe is the URL to pass as pageUrl here. Previews can be generated from an existing Ad ID, an Ad Creative ID, or by supplying a creative spec directly. See the Facebook Ad Previews documentation for details on generating preview URLs.
Note that requests to this endpoint are throttled and might take several minutes to complete.
Required parameters:
previews (array of objects) one or more Facebook ad previews to render. Each object has:
pageUrl (string) URL of the Facebook ad preview page (the iframe src from the Marketing API /generatepreviews response)Optional parameters (per preview):
previews
x (number) The horizontal CSS pixel offset from the top left corner of the document. Default value 0y (number) The vertical CSS pixel offset from the top left corner of the document. Default value 0width (number) CSS pixel dimensions of the creative viewport. The default value is 1000height (number) CSS pixel dimensions of the creative viewport. The default value is 1000locale (string) the language tag for the browser locale. The default value is en-USOptional parameters (top level):
bucketName (string) name of the S3 bucket where the images are uploaded, if different from the default bucket of the accountinitialDelay (number) milliseconds to wait before capturing the first slice, overriding the server defaultResponse object properties:
previews (array of objects) one result per input preview, in the same order. Each object is either a success or failure:
success (boolean) trueslices (array of objects) timed screen captures of the ad:
t (number) time stamp, number of milliseconds from the start of the animationurl (string) URL of the uploaded PNG imagewidth (number) the pixel width of the imageheight (number) the pixel height of the imagesuccess (boolean) falseerror (string) description of the failure{
previews: [
{
success: true,
slices: [
{
t: 0,
url: 'https://customer-bucket.s3.amazonaws.com/a1b2c3d4e5f6.png',
width: 300,
height: 250
},
{
t: 200,
url: 'https://customer-bucket.s3.amazonaws.com/f6e5d4c3b2a1.png',
width: 300,
height: 250
}
]
},
{
success: false,
error: "preview didn't load correctly"
}
],
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Predicts visual attention heatmaps for a video. Returns URLs to a heatmap video, a render video with the heatmap composited on top of the original, a JSON file containing the underlying heatmap data, and a per-frame focus timeline.
Required parameters:
videoUrl (string) URL of the input video to analyze. Data URLs (data:video/...;base64,...) are also accepted.Optional parameters:
bucketName (string) name of the S3 bucket where the results are uploaded, if different from the default bucket of the accountprogressCallbackUrl (string) URL that will receive POST callbacks with progress updates during processing. The callback body contains a JSON object with a state field (inference, precompute_heatmap, or render_heatmap) and, where applicable, a progress field (number between 0 and 1)Response object properties:
heatmap (string) URL of the heatmap videorender (string) URL of the render video (original video with heatmap composited on top)data (string) URL of a JSON file containing the raw heatmap datafocusTimeline (array of objects) per-frame focus data over the duration of the video. Each object contains:
t1 (number) frame start time in secondst2 (number) frame end time in secondsxyExpected (object or null) the expected gaze position in normalized [0, 1] coordinates, or null if the frame has no gaze data. Contains x (number) and y (number)intensityScore (number or null) focus intensity score on the range [0, 1], where 1 means highly focused gaze and 0 means dispersed gaze, or null if the frame has no gaze data{
heatmap: 'https://customer-bucket.s3.amazonaws.com/a1b2c3d4_heatmap.mp4',
render: 'https://customer-bucket.s3.amazonaws.com/a1b2c3d4_render.mp4',
data: 'https://customer-bucket.s3.amazonaws.com/a1b2c3d4.json',
focusTimeline: [
{ t1: 0.0, t2: 0.04, xyExpected: { x: 0.52, y: 0.31 }, intensityScore: 0.87 },
{ t1: 0.04, t2: 0.08, xyExpected: { x: 0.48, y: 0.35 }, intensityScore: 0.79 },
{ t1: 0.08, t2: 0.12, xyExpected: null, intensityScore: null }
],
task_id: 123,
passThrough: { customer_data: 'xyz' }
}
Returns the latest market data benchmarks for ad formats, broken down by country with a global weighted average.
The benchmark service is available on a separate host. Contact Viomba for the endpoint URL. The account must have benchmark access granted by Viomba.
This endpoint uses header-based authentication only (see Authentication with headers).
Optional parameters (query string):
day (string) date in YYYY-MM-DD format. Defaults to today's date. If no data exists for the requested day, the server will look back up to 365 days for the most recent available data per country.401 Authentication failed - missing or invalid headers, or inactive account403 Benchmark access not permitted - the account has not been granted benchmark access429 Rate limit exceededGET /api/benchmark?day=2026-04-02
x-auth-key: 2
x-auth-token: <secret from account_secret_key table>
{
"success": true,
"day": "2026-04-02",
"byCountry": [
{
"country": "fi",
"dataDate": "2026-04-02",
"byFormat": [
{
"media": "desktop",
"type": "display",
"width": 160,
"height": 600,
"seen": 0.288,
"viewtime": 2951
}
]
},
{
"country": "se",
"dataDate": "2026-04-01",
"byFormat": [
{
"media": "desktop",
"type": "display",
"width": 160,
"height": 600,
"seen": 0.088,
"viewtime": 1201
}
]
}
],
"global": {
"byFormat": [
{
"media": "desktop",
"type": "display",
"width": 160,
"height": 600,
"seen": 0.198,
"viewtime": 2155
}
]
}
}
Response object properties:
success (boolean) always true for successful responsesday (string) the requested day in YYYY-MM-DD formatbyCountry (array) per-country benchmark data
country (string) two-letter ISO country codedataDate (string) the actual date the data is from (YYYY-MM-DD). May differ from the requested day if lookback was usedbyFormat (array) benchmark data per ad format
media (string) "desktop" or "mobile"type (string) ad type, e.g. "display"width (number) ad format width in pixelsheight (number) ad format height in pixelsseen (number) average share of seen impressions on the range [0, 1]viewtime (number) average impression view time in millisecondsglobal (object) global weighted average across all weighted regions
byFormat (array) same format as byCountry[].byFormat