> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://dev.neurologyca.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://dev.neurologyca.com/_mcp/server.

# Video Analysis

POST https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis
Content-Type: multipart/form-data

Upload a video and receive **two analyses in parallel**:

1. **Video Analysis** — scores (likeability, authenticity, clarity, confidence),
   strengths, areas for improvement, time-series scores, labeled moments, and detailed feedback.
2. **Biometric Analysis** — triage classification, emotion detection,
   governance (action flags, recommended actions), and a scientific interpretation narrative.

***

### Response behavior

This endpoint has two response paths depending on how long the pipeline takes:

**`200 OK` — synchronous result**
The full analysis is returned immediately in the response body.
Typical for short videos where the pipeline completes within the synchronous window.

**`202 Accepted` — asynchronous result**
The pipeline is still running. The response body contains a `pollingUrl` and `sessionId`.
Poll `GET /api/v1/full-analysis/{sessionId}` until `status == "complete"`, then read `result`.

> **Expect `202` in production.** Most real-world videos take longer than the synchronous
> window. Always implement polling — do not assume a `200` will be returned.

#### Polling flow

```
POST /api/v1/full-analysis
  → 202 { sessionId, pollingUrl }

loop:
  GET /api/v1/full-analysis/{sessionId}
    → { status: "processing", progress: { phase, kpnPackagesSent, ... } }
  wait 3–5 seconds

until status == "complete":
  → { status: "complete", result: { video_analysis, biometric_analysis, transcript } }
```

Reference: https://dev.neurologyca.com/soft-skills/api-reference/full-analysis

## Authentication

- `Authorization` header (bearer token, required) — Your API key (e.g. ng\_xxx...). The Try it and generated code send it as `Authorization: Bearer <key>`. Alternatively use the X-API-Key header with the raw key.

## Servers

- `https://softskills-api-b1f382ab39be.herokuapp.com` (Softskills API, default)
- `http://127.0.0.1:8000` (Local development API)

## Request

### Body (multipart/form-data)

This endpoint expects a multipart form containing a file.

- `sessionId` (string, optional) — Optional session identifier
- `video` (file, required) — Video file to analyze (MP4, WebM, MOV, AVI, MKV)
- `transcript` (string, optional) — Optional session transcript. If empty or omitted, the API auto-generates one using Deepgram speech-to-text.
- `contextPhrase` (string, optional) — Scenario description for contextual profiling (e.g. "job interview practice", "sales pitch rehearsal").
- `mediapipeSamples` (string, optional) — Optional JSON array of MediaPipe face landmark samples

## Response

### 200

Combined analysis result from AI and engine

- `sessionId` (string, optional) — The session identifier echoed back.
- `video_analysis` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysis, optional) — Full AI video analysis.
- `engine_analysis` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysis, optional, nullable) — Biometric analysis. Null if engine is not configured or the pipeline fails.
- `engine_kpis` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineKpis, optional, nullable) — The 5 biometric KPIs derived from the transcript and sent to engine.
- `transcript` (string, optional, nullable) — Transcript used (user-provided or Deepgram-generated).
- `videoUrl` (string, optional, nullable) — Pre-signed S3 URL to view the uploaded video (expires in 1 hour).

### 202

Pipeline is still running — poll `pollingUrl` until `status == "complete"`, then read `result` from `GET /api/v1/full-analysis/{sessionId}`.

- `sessionId` (string, required)
- `jobId` (string, required, nullable)
- `pollingUrl` (string, required)
- `reason` (enum, required)
  - Allowed values: `video_too_long`, `timeout`
- `message` (string, required)
- `estimatedCompletionAt` (datetime, required)
- `createdAt` (datetime, required)

## Errors

### 401 Unauthorized Error

Invalid or expired API key

- `detail` (string, optional)

### 422 Unprocessable Entity Error

Missing or invalid request fields

- `any`

### 500 Internal Server Error

AI analysis failed (primary analysis)

- `any`

## Types

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysis

Full AI video analysis.

- `overall_score` (double, optional) — Overall performance score (0-100).
- `category_scores` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisCategoryScores, optional)
- `strengths` (list of string, optional)
- `areas_for_improvement` (list of string, optional)
- `detailed_feedback` (string, optional)
- `session_summary` (string, optional)
- `recommendation` (string, optional)
- `time_series_scores` (list of ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisTimeSeriesScoresItems, optional) — Scores per 10-second interval for charting.
- `labeled_moments` (list of ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisLabeledMomentsItems, optional) — Key delivery moments with behavioral labels.

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysis

Biometric analysis. Null if engine is not configured or the pipeline fails.

- `structured_data` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredData, optional) — Core analysis data.
- `interpretation` (string, optional) — Human-readable scientific narrative.
- `metadata` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisMetadata, optional)
- `warnings` (list of string, optional)

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineKpis

The 5 biometric KPIs derived from the transcript and sent to engine.

- `coherence` (double, optional) — Speech organization (0-100).
- `cognitive_effort` (double, optional) — Mental effort to produce speech (0-100).
- `rejection` (double, optional) — Rejection/resistance signals (0-100).
- `frustration` (double, optional) — Frustration level (0-100).
- `stress_intensity` (double, optional) — Stress intensity (0-100).

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisCategoryScores

- `likeability` (double, optional) — Likeability score (0-10).
- `authenticity` (double, optional) — Authenticity score (0-10).
- `clarity` (double, optional) — Clarity score (0-10).
- `confidence` (double, optional) — Confidence score (0-10).

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisTimeSeriesScoresItems

- `timestamp` (string, optional)
- `likeability` (double, optional)
- `authenticity` (double, optional)
- `clarity` (double, optional)
- `confidence` (double, optional)

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaVideoAnalysisLabeledMomentsItems

- `timestamp` (string, optional)
- `label` (string, optional)
- `text` (string, optional)

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredData

Core analysis data.

- `triage` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataTriage, optional) — Pattern classification (coherence_level, cognitive_effort_level).
- `emotion` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataEmotion, optional) — Detected emotion (term, coordinates, summaries).
- `governance` (ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataGovernance, optional) — Action flags, confidence score, recommended and proactive actions.
- `scientific_context` (string, optional) — Scientific evidence summary.

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisMetadata

- `model_version` (string, optional)
- `latency_ms` (double, optional)

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataTriage

Pattern classification (coherence_level, cognitive_effort_level).

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataEmotion

Detected emotion (term, coordinates, summaries).

### ApiV1FullAnalysisPostResponsesContentApplicationJsonSchemaEngineAnalysisStructuredDataGovernance

Action flags, confidence score, recommended and proactive actions.

## Examples

### Example 1

**Request**

```json
{
  "video": "<file: string>"
}
```

**Response**

```json
{
  "sessionId": "string",
  "video_analysis": {
    "overall_score": 1.1,
    "category_scores": {
      "likeability": 1.1,
      "authenticity": 1.1,
      "clarity": 1.1,
      "confidence": 1.1
    },
    "strengths": [
      "string"
    ],
    "areas_for_improvement": [
      "string"
    ],
    "detailed_feedback": "string",
    "session_summary": "string",
    "recommendation": "string",
    "time_series_scores": [
      {
        "timestamp": "string",
        "likeability": 1.1,
        "authenticity": 1.1,
        "clarity": 1.1,
        "confidence": 1.1
      }
    ],
    "labeled_moments": [
      {
        "timestamp": "string",
        "label": "string",
        "text": "string"
      }
    ]
  },
  "engine_analysis": {
    "structured_data": {
      "triage": {},
      "emotion": {},
      "governance": {},
      "scientific_context": "string"
    },
    "interpretation": "string",
    "metadata": {
      "model_version": "string",
      "latency_ms": 1.1
    },
    "warnings": [
      "string"
    ]
  },
  "engine_kpis": {
    "coherence": 1.1,
    "cognitive_effort": 1.1,
    "rejection": 1.1,
    "frustration": 1.1,
    "stress_intensity": 1.1
  },
  "transcript": "string",
  "videoUrl": "string"
}
```

**SDK Code**

```python
import requests

url = "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis"

files = { "video": "open('string', 'rb')" }
payload = {
    "sessionId": ,
    "transcript": ,
    "contextPhrase": ,
    "mediapipeSamples": 
}
headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, data=payload, files=files, headers=headers)

print(response.json())
```

```javascript
const url = 'https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis';
const form = new FormData();
form.append('sessionId', '');
form.append('video', 'string');
form.append('transcript', '');
form.append('contextPhrase', '');
form.append('mediapipeSamples', '');

const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

options.body = form;

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis"

	payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")
  .header("Authorization", "Bearer <token>")
  .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis', [
  'multipart' => [
    [
        'name' => 'video',
        'filename' => 'string',
        'contents' => null
    ]
  ]
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddParameter("undefined", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]
let parameters = [
  [
    "name": "sessionId",
    "value": 
  ],
  [
    "name": "video",
    "fileName": "string"
  ],
  [
    "name": "transcript",
    "value": 
  ],
  [
    "name": "contextPhrase",
    "value": 
  ],
  [
    "name": "mediapipeSamples",
    "value": 
  ]
]

let boundary = "---011000010111000001101001"

var body = ""
var error: NSError? = nil
for param in parameters {
  let paramName = param["name"]!
  body += "--\(boundary)\r\n"
  body += "Content-Disposition:form-data; name=\"\(paramName)\""
  if let filename = param["fileName"] {
    let contentType = param["content-type"]!
    let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8)
    if (error != nil) {
      print(error as Any)
    }
    body += "; filename=\"\(filename)\"\r\n"
    body += "Content-Type: \(contentType)\r\n\r\n"
    body += fileContent
  } else if let paramValue = param["value"] {
    body += "\r\n\r\n\(paramValue)"
  }
}

let request = NSMutableURLRequest(url: NSURL(string: "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
{
  "video": "<file: string>"
}
```

**Response**

```json
{
  "sessionId": "string",
  "jobId": "string",
  "pollingUrl": "/api/v1/full-analysis/session_1744567890123_abc123xyz",
  "reason": "video_too_long",
  "message": "string",
  "estimatedCompletionAt": "2024-01-15T09:30:00Z",
  "createdAt": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python
import requests

url = "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis"

files = { "video": "open('string', 'rb')" }
payload = {
    "sessionId": ,
    "transcript": ,
    "contextPhrase": ,
    "mediapipeSamples": 
}
headers = {"Authorization": "Bearer <token>"}

response = requests.post(url, data=payload, files=files, headers=headers)

print(response.json())
```

```javascript
const url = 'https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis';
const form = new FormData();
form.append('sessionId', '');
form.append('video', 'string');
form.append('transcript', '');
form.append('contextPhrase', '');
form.append('mediapipeSamples', '');

const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};

options.body = form;

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis"

	payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")
  .header("Authorization", "Bearer <token>")
  .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis', [
  'multipart' => [
    [
        'name' => 'video',
        'filename' => 'string',
        'contents' => null
    ]
  ]
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddParameter("undefined", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sessionId\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"video\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"transcript\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"contextPhrase\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"mediapipeSamples\"\r\n\r\n\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]
let parameters = [
  [
    "name": "sessionId",
    "value": 
  ],
  [
    "name": "video",
    "fileName": "string"
  ],
  [
    "name": "transcript",
    "value": 
  ],
  [
    "name": "contextPhrase",
    "value": 
  ],
  [
    "name": "mediapipeSamples",
    "value": 
  ]
]

let boundary = "---011000010111000001101001"

var body = ""
var error: NSError? = nil
for param in parameters {
  let paramName = param["name"]!
  body += "--\(boundary)\r\n"
  body += "Content-Disposition:form-data; name=\"\(paramName)\""
  if let filename = param["fileName"] {
    let contentType = param["content-type"]!
    let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8)
    if (error != nil) {
      print(error as Any)
    }
    body += "; filename=\"\(filename)\"\r\n"
    body += "Content-Type: \(contentType)\r\n\r\n"
    body += fileContent
  } else if let paramValue = param["value"] {
    body += "\r\n\r\n\(paramValue)"
  }
}

let request = NSMutableURLRequest(url: NSURL(string: "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```