Video Emotion API

Analyze emotions and facial expressions from video content.

Submit a video from multiple sources and receive detailed emotion analysis of all detected faces throughout the video timeline.

Input Sources:

  • YouTube: Provide any YouTube video URL
  • Cloud Storage: Dropbox, Google Drive, or other cloud service links
  • Social Media: Instagram, Facebook, Twitter (X) videos
  • Direct URL: Any publicly accessible video link
  • File Upload: Upload video files directly from your device

Analyze Specific Segments: Focus on specific portions using start_millis and end_millis parameters. This helps target key moments and optimize credit usage.

How It Works:

  1. Submit your video and receive an immediate response with a video ID
  2. Video is queued for processing (typically completes within minutes)
  3. Optionally receive a webhook notification via callback_url when complete
  4. Retrieve results using the video ID

Supported Formats: MP4, AVI, MOV, WebM, MPEG

Credit Usage: Billed on success; the amount is recorded after the run and is not quoted on this request. Each video is billed at least 10 credits. A 402 is returned before processing starts when admission is refused.

Moments: Set moments to run Moments on this video as part of the same request. It is billed with the analysis, and a single 402 covers both: when your balance cannot cover them together, nothing is charged and the video is not queued. If the video's first analysis fails, Moments is cancelled and you are not billed for it; once the video has been reprocessed, a later failure does not cancel it. Leave it off to request Moments later.

post/v2/videos

Request

  • Base URL
    https://api.imentiv.ai (the document declares no server; this is the origin it was published from)
  • Auth
    • API key in header X-API-Key
    • or HTTP bearer
    • or OAuth 2
      Authorization code: https://api.imentiv.ai/oauth/authorize
      Token URL: https://api.imentiv.ai/oauth/token scopes: media.write

Request body multipart/form-data

titlestring required

A descriptive title for your video (e.g., 'Team Meeting' or 'Customer Interview').

descriptionstring

Optional notes about the video content or context.

video_urlstring

URL to your video. Supported sources: YouTube, Dropbox, Instagram, Facebook, Twitter (X), or any direct video link. Leave empty if uploading a file instead.

start_millisnumber

Start point in milliseconds to begin analysis. Use 0 to start from the beginning. If provided (>0), end_millis is required with minimum 1-second (1000ms) gap.

end_millisnumber

End point in milliseconds to stop analysis. Use 0 only when analyzing the full video (start_millis must also be 0). If start_millis is provided, end_millis is required and must be at least 1000ms greater than start_millis.

callback_urlstring

Your webhook URL to receive a notification when analysis completes. Must be an https URL on a publicly reachable host.

video_filestring binary

Upload a video file directly (mp4, avi, mov, webm, mpeg). File upload takes priority over video_url.

project_idstring

Optional ID of a project you may modify (normally one you own). For an audience panel or user testing project, this video becomes its primary video. For a collection, this video is added to the collection; a delegated access token also needs the projects.write scope for that, and is refused with 403 insufficient_scope without it. An unknown project, or one you may not modify, returns 404. Any other project type returns 422: upload without project_id, then link the video to the project.

processing_fps15 | 10 | 5 | 1 nullable

Reduced processing frame rate (15, 10, 5, or 1 fps) that lowers the credit cost. Omit (or send empty/0) for full/native fps (no discount).

video_type'generic' | 'online_meeting' | 'auto' | 'in_vehicle'

Processing mode for face analysis. 'generic' (the default) skips on-screen name OCR. 'online_meeting' OCRs the participant-name labels a meeting client draws on each tile. 'auto' asks the library to decide from a bounded probe of the opening and reports the resolved mode back; it is opt-in and never the default, because its precision on non-meeting video is not yet characterised. 'in_vehicle' runs EXPERIMENTAL driver-state analysis (drowsiness and distraction) and requires the driver_state feature; 'auto' never resolves to it. Omit (or send empty) for generic. Unrecognised values — including the retired spelling 'meeting' — are rejected.

meeting_platform'zoom' | 'google_meet' | 'teams' | 'webex' nullable

Optional meeting-client hint (zoom, google_meet, teams, webex) that helps the OCR pipeline. Omit (or send empty) if unknown. Not required: the library is client-agnostic without it. Stored independently of video_type; the worker ignores the hint unless video_type is online_meeting.

use_case'interview' | 'product_testing' | 'sales_call' nullable

Optional: what the recording is. 'interview': a question-and-answer session, where moments rank slow answers and drops in engagement first. 'product_testing': viewers reacting to things shown in the video, ranked by their reaction to each stimulus; it needs stimuli. 'sales_call': a sales conversation, where moments focus on the customer's reactions and shifts in momentum. Omit when unsure. A project whose type selects its own analysis, or video_type='in_vehicle', takes precedence.

sales_callboolean

Place this video in your sales calls, a sales_deal project, so it is left out of the Default Library. The project is created the first time you ask. A delegated token needs only media.write. Used when project_id is omitted. A project_id this upload can link is used instead; any other project_id is still refused.

momentsboolean

Also run Moments on this video once its analysis finishes. If the video's first analysis fails, Moments is cancelled and you are not billed for it; once the video has been reprocessed, a later failure does not cancel it. Leave it off to request Moments later.

driver_position'left' | 'right' nullable

Optional seat hint for video_type='in_vehicle': which half of the VIDEO FRAME the driver appears in ('left' or 'right') — not the vehicle's drive side. Answer it by looking at the footage; it stays correct whatever the camera orientation or mirroring, whereas a drive-side answer does not and a wrong one silently analyses the passenger. Omit if unsure: the pipeline then picks the driver from track persistence and face size alone. Ignored unless video_type is in_vehicle.

driver_forward_gazestring nullable

Optional, video_type='in_vehicle' only: the direction the driver looks when looking straight ahead at the road, so driver attention can be measured from the first frame instead of being estimated from the footage. A JSON object {"yaw_deg": <number>, "pitch_deg": <number>} in degrees, camera-relative, in the same axes and sign as the gaze_yaw / gaze_pitch values returned for faces. yaw_deg must be within [-90, 90] and pitch_deg within [-60, 60]; both keys are required and no other keys are accepted. Example: {"yaw_deg": -20.0, "pitch_deg": 5.0}. Omit (or send empty) if unknown. Rejected with any other video_type.

camera_mount'steering_column' | 'dashboard_center' | 'windshield' | 'unknown' nullable

Optional, video_type='in_vehicle' only: where the camera is mounted ('steering_column', 'dashboard_center', 'windshield' or 'unknown'). A hint for the driver's straight-ahead direction when driver_forward_gaze is not supplied; an explicit driver_forward_gaze takes precedence. 'unknown' is recorded as sent (distinct from omitting the field) and provides no hint. Omit (or send empty) if not known. Rejected with any other video_type.

driver_forward_gaze_priorstring nullable

Optional, video_type='in_vehicle' only: a prior for the direction the driver looks when looking straight ahead at the road — typically the driver_state forward_gaze estimate returned for an earlier video from the same camera. A JSON object {"yaw_deg": <number>, "pitch_deg": <number>, "confidence": <number>} in degrees, camera-relative, in the same axes and sign as the gaze_yaw / gaze_pitch values returned for faces. yaw_deg and pitch_deg must be within [-90, 90]; confidence must be greater than 0 and at most 1. The forward_gaze object returned for a face may be sent unchanged: its method is ignored and its convention must be 'public'; no other keys are accepted. An explicit driver_forward_gaze, or a camera_mount of 'steering_column', takes precedence over a prior, and a low-confidence prior may not be applied. Example: {"yaw_deg": -20.0, "pitch_deg": 5.0, "confidence": 0.9}. Omit (or send empty) if unknown. Rejected with any other video_type.

diarizationboolean

Speaker diarization on the video's audio track. Enabled by default. Disabling this stage reduces the per-second credit cost.

text_emotionboolean

Text emotion analysis on the transcript. Enabled by default. Requires a transcript: ignored (forced off) when transcription is disabled and you supply no transcript. Supplying a transcript is the exception — the words already exist, so this is honoured as you sent it. Disabling this stage reduces the per-second credit cost.

transcriptionboolean

Transcript / ASR generation for the video's audio track. Enabled by default. When disabled, no transcript is produced and text_emotion is forced off. Supplying a transcript overrides this field entirely: our ASR is skipped either way, but your transcript is used and text_emotion still applies. Disabling this stage reduces the per-second credit cost.

languagestring nullable

Language code for the audio track (e.g. 'en'). Auto-detected if not provided. With expected_languages it must be one of them.

multilingualboolean

Opt in to mixed-language transcription: the speech may switch language, and each stretch is transcribed in the language it is spoken in. Once the audio completes, the lines that are not in its main language are also translated into the main language and billed as a translation, on top of transcription (auto_translation reports it). This is input only; the languages actually detected are reported separately.

expected_languagesstring nullable

Comma-separated codes of the languages the audio may contain, the main one included (e.g. en,ja), 1 to 5 after duplicates are removed. Case and whitespace are ignored, a region is dropped (pt-BR is pt) and an alias maps to the Whisper spelling (iw is he); Cantonese is yue. Language detection is restricted to the set, with or without multilingual. If language is also sent it must be one of them (422 invalid_language otherwise). If language is omitted, detection still runs, restricted to the set. An unknown code, or more than 5, is refused with 422 invalid_language before anything is charged.

transcriptstring

Optional: a transcript you already have for this video. When supplied we skip our own speech-to-text, use your transcript's speaker turns as the diarization, and name the speakers from it — so results come back with real participant names. Supplying one overrides transcription: our ASR is skipped either way, and you are charged less because that stage is not billed.

transcript_formatstring

Format of transcript. 'auto' (the default) detects it. Supported: 'auto', 'text', 'tldv_json', 'teams_vtt', 'zoom_vtt', 'vtt', 'srt'. Works with tl;dv, Zoom, Microsoft Teams, Otter, Fathom, Tactiq and most .vtt/.srt exports. Google Meet's own transcript is not supported yet — it timestamps only every 5 minutes, which cannot be aligned to the audio.

transcript_offset_millisinteger

Milliseconds added to every timestamp in transcript to place it on the media timeline. Positive means the transcript starts later than the recording (transcription began after record). Negative means it starts earlier (transcription running before record). 0 (the default) is today's behaviour. A negative offset that places any turn before 0 ms is rejected. Ignored when no transcript is supplied.

stimulistring nullable

Optional: when things the viewer reacts to appear in this video, for product testing, ad testing and reaction videos. A JSON array of objects {"label": str, "kind": "ad_start"|"scene"|"product_reveal"|"price"|"logo"|"question"|"cta"|"custom", "start_ms": int, "end_ms": int (optional), "id": str (optional), "meta": object (optional), "category": str (optional), "variant": str (optional), "response_window_ms": [int, int] (optional), "attribute_during_span": bool (optional)}, in milliseconds of video time. category is a grouping label of your own, 1-32 characters of A-Z, a-z, 0-9, '_', '.' or '-'. variant is a label for comparing versions of the same stimulus, 1-64 characters. For both, surrounding spaces are removed and case is kept, so " Cedar " is stored as "Cedar" and is a different value from "cedar". response_window_ms is [start, end] in milliseconds after the stimulus starts, 0 <= start < end <= 600000: a reaction that begins inside it is attributed to the stimulus; when omitted, the default window applies. attribute_during_span true also attributes a reaction that begins while the stimulus is on screen, and needs an end_ms after start_ms; false is the same as omitting it, is not stored and is returned as null. Every stimulus must start within the video and end no later than its end. At most 500 stimuli. Not accepted together with start_millis > 0. Example: [{"label": "Price screen", "kind": "price", "start_ms": 72000, "end_ms": 80000}].

non_human_spansstring nullable

Optional: known non-human audio, such as a voice assistant or music. A JSON array of {"start_ms": int, "end_ms": int, "role": "system"|"media", "label": str (optional)}, in milliseconds of the analysed video. end_ms is after start_ms and no later than the video's end. label, when present, is 1-80 characters after surrounding spaces are removed. At most 1000 spans. Not accepted together with start_millis > 0. Omitted, blank or [] means none. Example: [{"start_ms": 0, "end_ms": 4000, "role": "system", "label": "Voice assistant"}].

Response

Successful Response

idstring required
titlestring required
statusstring required
durationinteger required
media_sourcestring required
media_source_urlstring required
user_idstring required
created_atstring nullable
processing_fpsinteger nullable
processing_fps_autoboolean nullable
processing_fps_estimate_sinteger nullable
video_type'generic' | 'online_meeting' | 'auto' | 'in_vehicle' nullable
meeting_platform'zoom' | 'google_meet' | 'teams' | 'webex' nullable
use_case'interview' | 'product_testing' | 'sales_call' nullable
driver_position'left' | 'right' nullable
camera_mount'steering_column' | 'dashboard_center' | 'windshield' | 'unknown' nullable
diarizationboolean nullable
text_emotionboolean nullable
transcriptionboolean nullable
speaker_countinteger nullable

Changes

    • breaking

      the response's property type changed from array to string for status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      added the optional property to the response with the status

    • info

      the response property became required for the status

    • warning

      added the new sales_call enum value to the / response property for the response status

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new optional request property

    • info

      added the new sales_call enum value to the request property /