NAV Navbar
back icon Back
shell python javascript
Contact us

for a Developer API Key

3D

Introduction

Welcome to the SAIA API Documentation! You can use Person’s API endpoints to get a calculation for the front, side, volumes, and generate 3D models.

Authentication

To authorize, use this code:

import requests

session = requests.Session()
session.headers.update({
    'Authorization': "APIKey 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
    })
session.get('https://saia.3dlook.me/api/v2/persons/')
# With shell, you can just pass the correct header with each request
curl "https://saia.3dlook.me/api/v2/persons/"
  -H "Authorization: APIKey 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/",
    "method": "GET",
    "headers": {
        "Authorization": "Authorization: APIKey 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b",
        },
    "processData": false,
}
$.ajax(settings).done(function (response) {
});

Make sure to replace 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b with your API key.

SAIA uses API keys to allow access to the API. Please check your API key in your SAIA admin panel.

For clients to authenticate, include the token key in all API requests to the server in a header. The key should be prefixed by the string literal "APIKey" with a whitespace separating the two strings. For example:

Authorization: APIKey 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Correct Flow

To start a body params calculation, you need to create a Person object. Complete Person with all the required data for calculations, you can build it in two ways. It depends on your option to send base64 encoded photos:

Single Request

If it's ok for you to decode photos to Base64 format, you can:

Two Requests

If you'd like to send photos as files:

Correctly GET results

Incorrect Photo

If you got an error on the calculation task of side or front photo, you can:

Soft Validation Parameters

Parameter Validation Description
legs_distance > 2, < 15 Distance between legs, in cm
body_area_percentage = 0.7 Percentage of body on the photo

Person 3D Model

Create a New 3D Person

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>',
    'Content-Type': 'application/json'
}

payload = {
    'gender': 'female',
    'height': 170,
    "weight": 70.0
}

response = requests.request('POST', 'https://saia.3dlook.me/api/v2/persons/', data=payload, headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/"
  -X POST
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
  -d '{
    "gender": "female",
    "height": 170,
    "weight": 70.0
}'
var payload = {
    "gender": "female",
    "height": 170,
    "weight": 70.0
}

var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/",
    "method": "POST",
    "headers": {
    "Content-Type": "application/json",
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
    "data": payload
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "id": 3,
    "url": "https://saia.3dlook.me/api/v2/persons/3/",
    "gender": "female",
    "height": 170,
    "weight": 70.0
}

This endpoint creates a new person, with metadata first and then the partial update with front and side images, with all parameters with front image and side image Base64 encoded.

HTTP Request

POST https://saia.3dlook.me/api/v2/persons/

Request Body

The request body should be an "application/json" encoded object, containing the following items.

Parameter Type Validation Description
gender string male or female gender of person, male or female
height integer > 150, < 220 height of person, in cm
weight float float weight of person, in kg
front_image string image encoded to Base64 front photo of person
side_image string image encoded to Base64 side photo of person

Update a Specific 3D Person

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>',
    'Content-Type': 'application/json'
}

files={
    'front_image': open('path_to_file', 'rb'),
    'side_image': open('path_to_file', 'rb'),
}
response = requests.request('PUT', 'https://saia.3dlook.me/api/v2/persons/3/', files=files, headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/3/"
  -X PUT
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
  -F front_image=@/path/to/files/front_photo.jpg \
  -F side_image=@/path/to/files/side_photo.jpg
var form = new FormData();
form.append("front_image", "path_to_file");
form.append("side_image", "path_to_file");

var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/3/",
    "method": "PUT",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
    "contentType": false,
    "mimeType": "multipart/form-data",
    "data": form
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "task_set_url": "https://saia.3dlook.me/api/v2/queue/4d563d3f-38ae-4b51-8eab-2b78483b153e/"
}

Response also contains header:

"Location": "https://saia.3dlook.me/api/v2/queue/4d563d3f-38ae-4b51-8eab-2b78483b153e/"

This endpoint uploads front and side images to a new person if you are unable to send photos in Base64 encoding.

HTTP Request

PUT https://saia.3dlook.me/api/v2/persons/<id>/

URL Parameters

The following parameters should be included in the URL path.

Parameter Description
id The ID of the person created without front and side photo

Request Body

The request body should be a "multipart/form-data" encoded object, containing the following items.

Parameter Type Validation Description
front_image file correct image, filename with image extension front photo of person
side_image file correct image, filename with image extension side photo of person

Partial Update a Specific 3D Person

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>',
    'Content-Type': 'application/json'
}

files={
    'front_image': open('path_to_file', 'rb'),
    'side_image': open('path_to_file', 'rb'),
}
response = requests.request('PATCH', 'https://saia.3dlook.me/api/v2/persons/3/', files=files, headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/3/"
  -X PATCH
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
  -F front_image=@/path/to/files/front_photo.jpg \
  -F side_image=@/path/to/files/side_photo.jpg
var form = new FormData();
form.append("front_image", "path_to_file");
form.append("side_image", "path_to_file");

var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/3/",
    "method": "PATCH",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
    "contentType": false,
    "mimeType": "multipart/form-data",
    "data": form
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "front_image": "person/front_image_name.jpg",
    "side_image": "person/side_image_name.jpg"
}

Response also contains header:

This endpoint is required for the partial update of photos side or front in case you would like to rerun the calculation due to the error.

HTTP Request

PATCH https://saia.3dlook.me/api/v2/persons/<id>/

URL Parameters

The following parameters should be included in the URL path.

Parameter Description
id The ID of the person created without front and side photo

Request Body

The request body should be a "multipart/form-data" encoded object containing the following items.

Parameter Type Validation Description
front_image file correct image, filename with image extension front photo of person
side_image file correct image, filename with image extension side photo of person

Get a Specific 3D Person

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>'
}

response = requests.request('GET', 'https://saia.3dlook.me/api/v2/persons/545/', headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/545/"
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/545/",
    "method": "GET",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "id": 545,
    "url": "https://saia.3dlook.me/api/v2/persons/545/",
    "gender": "male",
    "height": 170,
    "weight": 70.0,
    "volume_params": {
        "chest": 101.081375,
        "waist": 89.826042,
        "low_hips": 109.4521824,
        "high_hips": 99.501984,
        "body_model": "https://storage.googleapis.com/saia-storage-test/persons/models/697340dd0c246ehb191ea9lb475bc4f.obj"
    },
    "front_params": {
        "outseam": 85.1134078687742,
        "inseam": 66.7249937989673,
        "body_area_percentage": 0.7680029074351,
        "legs_distance": 14.25707127270852,
        "shoulders": 43.5656540607115
    }
}

This endpoint retrieves a specific person with calculated params after all the calculation tasks are finished

HTTP Request

GET https://saia.3dlook.me/api/v2/persons/<id>/

URL Parameters

The following parameters should be included in the URL path.

Parameter Description
id The ID of the person with calculations to retrieve

List All 3D Persons

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>'
}

response = requests.request('GET', 'https://saia.3dlook.me/api/v2/persons/', headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/"
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/",
    "method": "GET",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "count": 20,
    "next": "https://saia.3dlook.me/api/v2/persons/?page=2",
    "previous": null,
    "results": [
        {
            "id": 546,
            "url": "https://saia.3dlook.me/api/v2/persons/546/",
            "gender": "male",
            "height": 170,
            "weight": 70.0,
            "volume_params": {
                "chest": 101.0,
                "waist": 89.8,
                "low_hips": 109.4,
                "high_hips": 99.5,
                "body_model": "https://storage.googleapis.com/saia-storage-test/persons/models/91391781fecc4b69b464e9f2d2ff901e.obj"
            },
            "front_params": {
                "outseam": 85.1,
                "inseam": 66.7,
                "body_area_percentage": 0.76,
                "legs_distance": 14.2,
                "shoulders": 43.5
            }
        },
        {
            "id": 545,
            "url": "https://saia.3dlook.me/api/v2/persons/545/",
            "gender": "male",
            "height": 170,
            "weight": 70.0,
            "volume_params": {
                "chest": 101.0,
                "waist": 89.8,
                "low_hips": 109.4,
                "high_hips": 99.5,
                "body_model": "https://storage.googleapis.com/saia-storage-test/persons/models/64b7340dd0c246edb191ea9db475bc4f.obj"
            },
            "front_params": {
                "outseam": 85.1,
                "inseam": 66.7,
                "body_area_percentage": 0.76,
                "legs_distance": 14.2,
                "shoulders": 43.5
            }
        }
    ]
}

This endpont retrieves all your existing persons with calculations.

HTTP Request

GET https://saia.3dlook.me/api/v2/persons/

Query Parameters

The following parameters should be included as part of the URL query string.

Parameter Default Description
page A page number within the paginated result set.

Manually Start Calculations of a Specific 3D Person

import requests

headers = {
    'Authorization': 'APIKey <YOUR_API_KEY_HERE>'
}

response = requests.request('GET', 'https://saia.3dlook.me/api/v2/persons/545/calculate/', headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/persons/545/calculate/"
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/persons/545/calculate/",
    "method": "GET",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "task_set_url": "https://saia.3dlook.me/api/v2/queue/4d563d3f-38ae-4b51-8eab-2b78483b153e/"
}

This endpoint manually runs calculations of all params after Partial Update of photos of a specific person. As a result, you will get a URL for task_set where the info can be tracked.

HTTP Request

GET https://saia.3dlook.me/api/v2/persons/<id>/calculate/

URL Parameters

The following parameters should be included in the URL path.

Parameter Description
id The ID of the person with calculations to retrieve

Get a Specific Task Set

import requests

headers = {
    'Authorization': "APIKey <YOUR_API_KEY_HERE>"
}

response = requests.request('GET', 'https://saia.3dlook.me/api/v2/queue/6a885ee2-153a-4cc4-9111-fbee31738410/', headers=headers)
print(response.text)
curl "https://saia.3dlook.me/api/v2/queue/6a885ee2-153a-4cc4-9111-fbee31738410/"
  -H "Authorization: APIKey <YOUR_API_KEY_HERE>"
var settings = {
    "async": true,
    "crossDomain": true,
    "url": "https://saia.3dlook.me/api/v2/queue/6a885ee2-153a-4cc4-9111-fbee31738410/",
    "method": "GET",
    "headers": {
        "Authorization": "APIKey <YOUR_API_KEY_HERE>",
        },
    "processData": false,
}

$.ajax(settings).done(function (response) {
console.log(response);
});

The above command returns JSON structured like this:

{
    "is_successful": false,
    "is_ready": false,
    "sub_tasks": [
        {
            "name": "unrecognized_task",
            "status": "PENDING",
            "task_id": "6bbe7942-eadd-4bd2-84c8-c03f9c6a2f7a",
            "message": ""
        },
        {
            "name": "unrecognized_task",
            "status": "PENDING",
            "task_id": "10324eb8-c60f-4b20-baed-9c66d9ca9e66",
            "message": ""
        },
        {
            "name": "unrecognized_task",
            "status": "PENDING",
            "task_id": "10324eb8-c60f-4b20-baed-9c66d9ca9e66",
            "message": ""
        }
    ]
}

Returns information of given task-set:

HTTP Request

GET https://saia.3dlook.me/api/v2/queue/<task_set_id>/

URL Parameters

Parameter Description
task_set_id The id of the task_set to retrieve

Integration

Javascript SDK for SAIA 3D API

SAIA Javascript SDK.

Render library for SAIA 3D API

Model Renderer.

Errors

HTTP Errors

The SAIA API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is incorrect.
403 Forbidden -- Access to the requested API is forbidden.
404 Not Found -- The specified item could not be found.
406 Not Acceptable -- You requested a non-JSON format.
422 Unprocessable Entity -- One or both of the uploaded photos could not be processed.
429 Too Many Requests -- You are sending too many requests.
500 Internal Server Error -- A server error occured. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Task Errors

Asynс Params Calculation Tasks uses the following error codes:

Application Code Message Meaning
900 The pose is wrong, check your <body_part> The pose of the human body in one or both of the uploaded photos is wrong and we cannot process the human body.
901 Сan not detect the human body The human body in the photo cannot be detected.
902 The detected object is not human The detected object in the photo is not a human body and it cannot be processed.
903 Side photo in the front The photo uploaded to the Front slot detected to be a Side photo.
904 The body is not full The photo does not contain the whole body.

Soft Validation Errors

Each returned person's JSON could include objects(for Front and Side photos) with recommendation message for users how they can get more accurate calculation results(Soft validation):

Application Code Message Meaning
920 Keep your head straight Head tilt detected.
921 Keep your hands at waist level Hand placement detected at hips or chest levels.
922 Check your <body_part> Minor problem(s) detected with one or multiple body part(s).

How-To

Step-by-step guides for your use cases

Basic SDK flow example

<label for="front_image">
    <input type="file" name="front_image" id="front_image">
</label>

Choose front image:

<label for="side_image">
    <input type="file" name="side_image" id="side_image">
</label>

Choose side image:

<label for="gender">
  <select name="gender" id="gender">
    <option value="male">male</option>
    <option value="female">female</option>
  </select>
</label>

Choose gender:

<label for="height">
  <input type="number" name="height" id="height" value="170">
</label>

<p>Execution status: <span id="status"></span></p>
<button id="start" type="button">START</button>
<pre id="results" class="results"></pre>

Enter height:

import SAIA from ‘@3dlook/saia-sdk’;

const frontImage = document.getElementById('front_image');
const sideImage = document.getElementById('side_image');
const gender = document.getElementById('gender');
const height = document.getElementById('height');
const startBtn = document.getElementById('start');
const results = document.getElementById('results');
const status = document.getElementById('status');

const saia = new SAIA({
  key: '<YOUR_API_KEY>',
});

Import SAIA SDK class:

startBtn.addEventListener('click', () => {
  let frontImage64;
  let sideImage64;

  // convert front image to base64
  saia.utils.getBase64(frontImage.files[0])
    .then((base64) => {
      frontImage64 = base64;

      // convert side image to base64
      return saia.utils.getBase64(sideImage.files[0]);
    })
    .then((base64) => {
      sideImage64 = base64;

      // create person with gender, height and images
      return saia.api.person.create({
        gender: gender.value,
        height: height.value,
        frontImage: frontImage64,
        sideImage: sideImage64,
      });
    })
    .then((taskSetId) => {
      status.innerHTML = 'Processing...';

      // check person processing and get the result
      return saia.api.queue.getResults(taskSetId);
    })
    .then((person) => {
      status.innerHTML = 'Finished';


      // print the result out
      results.innerHTML = JSON.stringify(person, null, '  ');
    })
    .catch((e) => {
      console.log(e);
    });
});

Set the start button click event handler to start the flow

One step form wireframe

This form must consist of the following mandatory fields:

One step form wireframe

Height input field(s)

Height must be more or equal to 150cm (4’ 11”) and less or equal to 220cm (7’ 2”).

Min height in cm. Height should be more or equal to 150cm

One step form wireframe

Max height in cm. Height should be less or equal to 220cm

One step form wireframe

Min height in inches. Height should be more or equal to 4’ 11’’

One step form wireframe

Max height in inches. Height should be less or equal to 7’ 2’’

One step form wireframe

/**
 * Convert centimeters value to feet and inches
 *
 * @param {number} cm - centimeters
 * @returns {Object} object with foot-inch values
 */
const cmToFtIn = (cm) => {
  const inches = cm / 2.54;
  const ft = inches / 12;

  return {
    ft: Math.floor(ft),
    in: Math.ceil(inches.toFixed(0) % 12),
  };
};

Function for converting centimeters to foot-inch values:

/**
 * Convert inches to centimeters
 *
 * @param {number} inches - inches
 * @returns {number} centimeters value
 */
const in2cm = inches => inches * 2.54;

Function for converting inches to centimeters:

/**
 * Convert ft to in value
 *
 * @param {number} ft - foot value
 * @returns {number} inch value
 */
const ft2in = ft => ft * 12;

Function for converting feet to inches:

/**
 * Convert ft and in height to cm value
 *
 * @param {number} ft - foot value
 * @param {number} inches - inch value
 */
const getHeightCm = (ft = 0, inches = 0) => {
  return in2cm(ft2in(ft) + parseInt(inches, 10));
};

Function for converting foot-inch value to centimeters

Gender radio buttons

The best practice is to show the outlines of the body according to the specified gender

Gender specified as Female

Gender specified as Female

Gender specified as Male

Gender specified as Male

Slots for front and side photos

1. When the slots are empty

When the slots are empty

In the description of each slot, a user must see the full information about what must be done:

2. User has uploaded photos

When the slots are empty

Image rotation fix https://gist.github.com/pisarivskiy/b68a5bd3e31c59586f99c60008e6f9eb#file-image-orientation-fix-example-js

$('#load-file').on('change', function () {
  var file = $(this).files[0];

  getOrientation(file)
    .then(function (fixOrientation) {
      return loadPhoto(file, fixOrientation);
    })
    .then(function (file) {
      img.attr('src', file);
    })
    .catch(function (err) {
      console.log(err);
    });
});

This code checks EXIF flag in the image file metadata and rotates it based on this flag. You need to get a blob object from input element with change event.

The result of loadPhoto method (base64 encoded image) can be sent to our API.

If a user fills in the form correctly

user fills in the form correctly

function handleSubtaskErrors(subtasks) {
  const front = subtasks.filter(function (item) { return item.name.indexOf('front_') !== -1; })[0];
  const side = subtasks.filter(function (item) { return item.name.indexOf('side_') !== -1; })[0];

  if (front && front.status === 'FAILURE') {
    frontPhoto.classList.add('error');
  }

  if (side && side.status === 'FAILURE') {
    sidePhoto.classList.add('error');
  }
}

Errors messages and errors validation

If saia.api.queue.getResults returns an error, you could handle it in the following way to properly identify the image that produces the error

Errors messages and errors validation

Errors messages and errors validation

Recommendations:

Please retake the photo.

Check if you’ve followed through all of our recommendations:

If a user uploaded a wrong front photo

If a user uploaded a wrong side photo

Recommendations:

Please retake the photo.

Check if you’ve followed through all of our recommendations:

If a user uploaded a wrong side photo

If a user uploaded a wrong side photo

Recommendations:

Please retake the photo.

Check if you’ve followed through all of our recommendations:

Two step form wireframe

The form in can be done in two steps. See the example below:

Mandatory fields for the First Step:

First Step

Mandatory fields for the Second Step:

First Step

Render 3d model

import ModelRenderer from ‘@3dlook/model-renderer’;

Frist, import model-renderer package

<div id="canvas-container" style="width: 1280px; height: 720px;"></div>

Then, add canvas element

var m = new ModelRenderer({
    container: '#canvas-container',
  });
  m.init();

m.loadModel(MODEL_URL)
  .then(r => m.displayModel(r))
  .catch(err => alert(err.message));

After this create an instance of ModelRenderer and initialize it with 3d model url

Postman Examples