Getting Started

1. Create an API key

API key format

  • Keys start with ng_.
  • The preferred auth header is Authorization: Bearer <token>.
  • The alternative auth header is X-API-Key: <token>.

2. Authenticate requests

Preferred

1Authorization: Bearer ng_your_full_api_key_here

Alternative

1X-API-Key: ng_your_full_api_key_here

If you send Authorization: ng_xxx... without the Bearer prefix, the API returns 401 Unauthorized.


3. Submit a full-analysis request

Endpoint

1POST /api/v1/full-analysis

Base URL: https://softskills-api-b1f382ab39be.herokuapp.com

Request type

multipart/form-data

Request fields

FieldTypeRequiredDefaultNotes
videofileYesMP4, WebM, MOV, AVI, MKV
sessionIdstringNoapi_sessionSession identifier
transcriptstringNo""Pre-existing transcript; Deepgram is used if empty
contextPhrasestringNoprofessional communication coaching sessionForwarded to Engine

Example request

$curl -X POST "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis" \
> -H "Authorization: Bearer ng_your_api_key_here" \
> -F "video=@/path/to/your/video.mp4" \
> -F "sessionId=api_session" \
> -F "contextPhrase=professional communication coaching session"

Response behavior

Expect 202 Accepted in production. Most real-world videos exceed the synchronous processing window. Always implement the polling flow below — do not assume a 200 OK will be returned.

StatusWhenWhat to do
200 OKPipeline completed within the sync window (short videos)Read the result directly from the response body
202 AcceptedPipeline is still running (most production videos)Poll GET /api/v1/full-analysis/{sessionId} until status == "complete"

Polling flow

POST /api/v1/full-analysis
→ 202 { sessionId, pollingUrl, estimatedCompletionAt }
loop every 3–5 seconds:
GET /api/v1/full-analysis/{sessionId}
→ { status: "processing", progress: { phase, kpnPackagesSent, ... } }
until status == "complete":
→ { status: "complete", result: { video_analysis, biometric_analysis, transcript } }

Example 200

1{
2 "sessionId": "api_session",
3 "video_analysis": {
4 "overall_score": 85,
5 "category_scores": {
6 "likeability": 8,
7 "authenticity": 8,
8 "clarity": 9,
9 "confidence": 8
10 },
11 "strengths": ["Clear structure"],
12 "areas_for_improvement": ["Add more vocal variety"],
13 "filler_word_count": 2,
14 "speaking_pace_wpm": 112,
15 "labeled_moments": [
16 { "timestamp": "0:00", "label": "Engaged", "text": "Thanks for taking the time to meet with me today." }
17 ],
18 "time_series_scores": [
19 { "timestamp": "0:00", "likeability": 65, "authenticity": 90, "clarity": 80, "confidence": 70 }
20 ],
21 "detailed_feedback": "Clear communication overall with good structure and delivery.",
22 "session_summary": "Strong overall delivery with room for more vocal range.",
23 "recommendation": "Practice emphasizing key transitions."
24 },
25 "biometric_analysis": {
26 "classification": "Pattern C",
27 "coherence_level": "Low",
28 "cognitive_effort_level": "High",
29 "emotion": "Light-hearted",
30 "emotion_valence": 42,
31 "emotion_intensity": 64.5,
32 "emotion_quadrant": 1,
33 "cognitive_summary": "Speaker appears to be working hard to maintain structure.",
34 "emotional_summary": "Emotion remains steady and positive.",
35 "behavioral_summary": "Delivery is engaged but somewhat effortful.",
36 "adaptive_context": "Interview-style communication with moderate pressure.",
37 "governance_rationale": "No escalation indicators were detected.",
38 "governance_confidence": 0.95,
39 "recommended_actions": ["Slow down before transitions"],
40 "action_flags": { "flag_1": false, "flag_2": false, "flag_3": false },
41 "hci_priorities": {
42 "political_performance": 92,
43 "comprehension": 85,
44 "cognitive_effort": 68,
45 "confidence": 45
46 },
47 "scientific_context": "Pattern suggests elevated effort despite adequate comprehension.",
48 "model_version": "0.1.0",
49 "latency_ms": 12657.61
50 },
51 "transcript": "Thanks for taking the time to meet with me today."
52}

Example 202

1{
2 "sessionId": "api_session",
3 "jobId": "123e4567-e89b-12d3-a456-426614174000",
4 "pollingUrl": "/api/v1/full-analysis/api_session",
5 "reason": "video_too_long",
6 "message": "Video accepted for asynchronous processing.",
7 "estimatedCompletionAt": "2026-04-13T00:00:00Z",
8 "createdAt": "2026-04-13T00:00:00Z"
9}

4. Fetch a saved analysis by session

Endpoint

1GET /api/v1/full-analysis/{session_id}

Example request

$curl "https://softskills-api-b1f382ab39be.herokuapp.com/api/v1/full-analysis/session_1744567890123_abc123xyz" \
> -H "Authorization: Bearer ng_your_api_key_here"

Example in-flight response

1{
2 "status": "processing",
3 "sessionId": "session_1744567890123_abc123xyz",
4 "userId": "usr_abc123",
5 "createdAt": "2026-04-13T20:10:00.000Z",
6 "updatedAt": "2026-04-13T20:10:03.000Z",
7 "jobId": "3f2a1b4c-1111-2222-3333-444444444444",
8 "progress": {
9 "phase": "gemini",
10 "kpnPackagesSent": 12,
11 "kpnPackagesTotal": 30,
12 "enginePolls": 4
13 },
14 "result": null,
15 "error": null
16}

Example complete response

1{
2 "status": "complete",
3 "sessionId": "session_1744567890123_abc123xyz",
4 "userId": "usr_abc123",
5 "createdAt": "2026-04-13T20:10:00.000Z",
6 "updatedAt": "2026-04-13T20:11:45.000Z",
7 "jobId": null,
8 "progress": null,
9 "error": null,
10 "result": {
11 "video_analysis": {
12 "overall_score": 64,
13 "category_scores": {
14 "likeability": 6,
15 "authenticity": 5,
16 "clarity": 7,
17 "confidence": 5
18 },
19 "strengths": ["Strong opener", "Good eye contact"],
20 "areas_for_improvement": ["Improve confidence", "Reduce hesitations"],
21 "filler_word_count": 2,
22 "speaking_pace_wpm": 112,
23 "labeled_moments": [
24 { "timestamp": "0:00", "label": "Engaged", "text": "Okay, so I'm going to do a test here..." }
25 ],
26 "time_series_scores": [
27 { "timestamp": "0:00", "likeability": 65, "authenticity": 90, "clarity": 80, "confidence": 70 }
28 ],
29 "detailed_feedback": "Delivery is clear but confidence fluctuates.",
30 "session_summary": "Solid structure with noticeable effort and some hesitation.",
31 "recommendation": "Slow down and add deliberate pauses before key points."
32 },
33 "biometric_analysis": {
34 "classification": "Pattern C",
35 "coherence_level": "Low",
36 "cognitive_effort_level": "High",
37 "emotion": "Light-hearted",
38 "emotion_valence": 42,
39 "emotion_intensity": 64.5,
40 "emotion_quadrant": 1,
41 "cognitive_summary": "Elevated effort with weaker coherence.",
42 "emotional_summary": "Affect remains positive despite effort.",
43 "behavioral_summary": "Presenter stays engaged but appears strained.",
44 "adaptive_context": "The setting suggests a practice communication exercise.",
45 "governance_rationale": "No governance issues detected.",
46 "governance_confidence": 0.95,
47 "recommended_actions": ["Add pauses", "Rehearse difficult transitions"],
48 "action_flags": { "flag_1": false, "flag_2": false, "flag_3": false },
49 "hci_priorities": {
50 "political_performance": 92,
51 "comprehension": 85,
52 "cognitive_effort": 68,
53 "confidence": 45
54 },
55 "scientific_context": "Pattern suggests substantial effort despite adequate comprehension.",
56 "model_version": "0.1.0",
57 "latency_ms": 12657.61
58 },
59 "transcript": "Okay, so I'm going to do a test here..."
60 }
61}

Example failed response

1{
2 "status": "failed",
3 "sessionId": "session_1744567890123_abc123xyz",
4 "userId": "usr_abc123",
5 "createdAt": "2026-04-13T20:10:00.000Z",
6 "updatedAt": "2026-04-13T20:10:30.000Z",
7 "jobId": null,
8 "progress": null,
9 "result": null,
10 "error": "Pipeline error: upstream analysis failed."
11}

5. Error responses

StatusMeaning
401Missing or invalid API key
404Resource not found or job expired
413Video too long for sync without S3/Redis configured
500Internal pipeline error
503Redis not configured for async processing

Saved analyses may still return 404 if the session does not exist or is no longer available.


Summary

  • The surfaced SoftSkills flow is now POST /api/v1/full-analysis plus GET /api/v1/full-analysis/{session_id}.
  • Requests use multipart/form-data with a required video field.
  • Authentication uses Authorization: Bearer <token> or X-API-Key: <token>.
  • Short videos can return 200 immediately; longer runs return 202 and should be fetched later by sessionId.