Interviews API
An interview is one recorded AI session for one trader. Create it, send the link, read the report, record your decision.
Lifecycle#
created (link sent) then consented, in_progress (recording), submitted (trader finished) and report_ready (awaiting your decision). failed means the pipeline could not produce a report. expired is computed from expires_at for links never started. The decision (approved, rejected, needs_review) is independent of the status.
The interview object#
List endpoints return InterviewListItem. The detail endpoint returns InterviewDetail, which extends it.
| Field | Type | Description |
|---|---|---|
id | uuid | Interview identifier. |
trader | object | Trader id, name, email, external_id. |
status | SessionStatus | One of created, consented, in_progress, submitted, report_ready, failed. |
expired | boolean | True when the invite expired before the trader started. |
language | string | null | Interview language code. |
risk_score | low | medium | high | null | Set once the report is ready. |
recommended_step | approve | human_review | reject_escalate | null | The AI recommendation. |
decision | approved | rejected | needs_review | null | Analyst decision, with decided_at. |
assigned_to | object | null | Analyst id and name. |
media | MediaSummary[] | Per track (webcam, screen, mic): status, duration_ms, error. |
created_at, started_at, submitted_at, expires_at | timestamp | Key moments of the session. |
communication_done_at | timestamp | null | When your team closed the loop with the trader. |
sort_at | timestamp | Last activity, used for ordering. |
Detail only fields
| Field | Type | Description |
|---|---|---|
report | Report | null | The AI assessment, see below. |
answers | Answer[] | Transcript: question_text, answer_text, answer_english, input_mode, speech timings. |
events | IntegrityEvent[] | Integrity signals with type and offset_ms from recording start. |
activity_summary | ActivitySummary | null | Trading stats and breaches with hard or soft severity. |
activity_source | auto | csv | dev_fixture | null | Where the activity came from. |
environment | production | sandbox | Sandbox sessions are short and not billed. |
capture_mode | desktop | mobile | Capture mode of the session. |
duration_ms, ip_address, user_agent, start_connection_mbps | mixed | Session facts. |
technical_analysis | object | enabled, symbol, date, transcript of the chart narration. |
decision_detail | object | Decision, AI assessment, error direction, reasons, confirmed behaviors, note, decider. |
share | object | Share link state: active, url, expires_at. |
invite | object | url, expires_at, opened. |
trader_rating, trader_feedback | number | string | null | What the trader said about the experience. |
redo_of_session_id | uuid | null | Set on retakes. |
Report
{
"summary": "Consistent discretionary scalper, but seven positions mirror account 99840.",
"answers_summary": "Explains a London open strategy on EURUSD and GBPUSD ...",
"risk_score": "medium",
"recommended_step": "human_review",
"reason": "Opposite positions within 40 seconds on a second account.",
"activity_label": "Scalping, one sided",
"bullets": [
"Seven EURUSD positions opened within 40 s of opposite trades on acc_99840",
"Strategy description matches the trade history on timing and size"
],
"verdicts": { "third_party": "clear", "cross_account": "likely", "gamification": "suspected" },
"flags": ["tab_hidden", "paste"],
"risk_synthesis": {
"pre_interview": "...",
"post_interview": "...",
"conclusion": "...",
"cross_checks": [{ "claim": "Trades alone", "evidence": "...", "verdict": "supported" }],
"limitations": "Only 90 days of trades were available."
},
"model": "...",
"generated_at": "2026-09-23T11:42:10Z",
"decision_trace": {}
}Each verdict is clear, suspected or likely.
Endpoints#
GET/v1/interviewsinterviews:read
Returns InterviewPage
Paginated list with organization wide KPIs.
| Query | Type |
|---|---|
page, limit | number |
status | SessionStatus, active or expired |
risk | low | medium | high |
decision | Decision or pending |
search | string |
assigned_to | uuid, me or unassigned |
trader_id | uuid |
archived | boolean |
{ "total": 412, "in_progress": 3, "awaiting_review": 11, "decided_7d": 38, "approval_rate_30d": 0.71, "avg_duration_min": 21.4 }POST/v1/interviewsinterviews:create
Returns InterviewCreated
| Field | Type | Description |
|---|---|---|
trader_id | uuid | null | An existing trader. |
trader | object | null | Or inline: full_name, email, external_id. |
account_id | uuid | null | Focus the interview on one trading account. |
language | string | null | Defaults to your organization setting. The trader can change it. |
analyst_guidance | string | null | Private instructions for the interviewer and the report. |
window_hours | number | null | Link validity, 24 to 168 hours. |
technical_analysis | object | null | enabled, optional symbol and date for the chart part. |
sandbox | boolean | Short, unbilled test session. |
Returns interview, invite_url and expires_at. The invite URL is shown once.
GET/v1/interviews/{id}interviews:read
Returns InterviewDetail
POST/v1/interviews/{id}/decisioninterviews:decide
Returns InterviewDetail
| Field | Type | Description |
|---|---|---|
decision | approved | rejected | needs_review | Required. |
ai_assessment | correct | partially | wrong | null | How right the AI was. |
error_direction | over_flagged | under_flagged | null | When the AI was wrong. |
ai_error_reasons | string[] | Why the AI was wrong. |
confirmed_behaviors | string[] | Behaviors your team confirmed. |
reason, note | string | null | Decision reason and internal note. |
needs_review_reason | string | null | What is still open. |
POST/v1/interviews/{id}/reissue
Returns { invite_url, expires_at }
Issues a fresh invite link before the trader started, optionally with a new window_hours. The previous link stops working.
POST/v1/interviews/{id}/retake
Returns InterviewCreated
Creates a new interview for the same trader, linked through redo_of_session_id.
POST/v1/interviews/{id}/regenerate
Returns { queued: boolean }
Queues a new report, for example after uploading an activity file.
POST/v1/interviews/{id}/playbackinterviews:read
Returns Playback
Returns short lived signed HLS and DASH URLs per track, plus expires_at (unix seconds) and refresh_after_ms. Call it again before expiry to keep playing without losing the position. Tracks whose status is not ready are still processing: poll every 12 seconds.
GET/v1/interviews/{id}/subtitlesinterviews:read
Returns text/vtt
WebVTT captions. Answers 404 until built.
POST/v1/interviews/{id}/subtitles
Returns { queued: boolean }
POST/v1/interviews/{id}/activity-file
Returns InterviewDetail
Multipart upload with a file field: a CSV or XLSX trade export, used when no integration covers the account.
curl https://api.rubikyt.com/v1/interviews/$ID/activity-file \
-H "Authorization: Bearer $RUBI_API_KEY" \
-F "file=@trades.csv"GET/v1/interviews/{id}/activity-file
Downloads the uploaded activity file.
POST/v1/interviews/{id}/assign
Returns InterviewDetail
Body { "user_id": "uuid" }, or null to unassign.
PATCH/v1/interviews/{id}/communication
Returns InterviewDetail
Body { "done": true } marks that the outcome was communicated to the trader.
DELETE/v1/interviews/{id}interviews:delete
Deletes the interview, its media and transcript. Answers 204.