Skip to content

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.

FieldTypeDescription
iduuidInterview identifier.
traderobjectTrader id, name, email, external_id.
statusSessionStatusOne of created, consented, in_progress, submitted, report_ready, failed.
expiredbooleanTrue when the invite expired before the trader started.
languagestring | nullInterview language code.
risk_scorelow | medium | high | nullSet once the report is ready.
recommended_stepapprove | human_review | reject_escalate | nullThe AI recommendation.
decisionapproved | rejected | needs_review | nullAnalyst decision, with decided_at.
assigned_toobject | nullAnalyst id and name.
mediaMediaSummary[]Per track (webcam, screen, mic): status, duration_ms, error.
created_at, started_at, submitted_at, expires_attimestampKey moments of the session.
communication_done_attimestamp | nullWhen your team closed the loop with the trader.
sort_attimestampLast activity, used for ordering.

Detail only fields

FieldTypeDescription
reportReport | nullThe AI assessment, see below.
answersAnswer[]Transcript: question_text, answer_text, answer_english, input_mode, speech timings.
eventsIntegrityEvent[]Integrity signals with type and offset_ms from recording start.
activity_summaryActivitySummary | nullTrading stats and breaches with hard or soft severity.
activity_sourceauto | csv | dev_fixture | nullWhere the activity came from.
environmentproduction | sandboxSandbox sessions are short and not billed.
capture_modedesktop | mobileCapture mode of the session.
duration_ms, ip_address, user_agent, start_connection_mbpsmixedSession facts.
technical_analysisobjectenabled, symbol, date, transcript of the chart narration.
decision_detailobjectDecision, AI assessment, error direction, reasons, confirmed behaviors, note, decider.
shareobjectShare link state: active, url, expires_at.
inviteobjecturl, expires_at, opened.
trader_rating, trader_feedbacknumber | string | nullWhat the trader said about the experience.
redo_of_session_iduuid | nullSet on retakes.

Report

json
{
  "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.

QueryType
page, limitnumber
statusSessionStatus, active or expired
risklow | medium | high
decisionDecision or pending
searchstring
assigned_touuid, me or unassigned
trader_iduuid
archivedboolean
kpis
{ "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

FieldTypeDescription
trader_iduuid | nullAn existing trader.
traderobject | nullOr inline: full_name, email, external_id.
account_iduuid | nullFocus the interview on one trading account.
languagestring | nullDefaults to your organization setting. The trader can change it.
analyst_guidancestring | nullPrivate instructions for the interviewer and the report.
window_hoursnumber | nullLink validity, 24 to 168 hours.
technical_analysisobject | nullenabled, optional symbol and date for the chart part.
sandboxbooleanShort, 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

FieldTypeDescription
decisionapproved | rejected | needs_reviewRequired.
ai_assessmentcorrect | partially | wrong | nullHow right the AI was.
error_directionover_flagged | under_flagged | nullWhen the AI was wrong.
ai_error_reasonsstring[]Why the AI was wrong.
confirmed_behaviorsstring[]Behaviors your team confirmed.
reason, notestring | nullDecision reason and internal note.
needs_review_reasonstring | nullWhat is still open.

POST/v1/interviews/{id}/share

Returns ShareLink

Body { "expires_hours": 48 }. Creates a read only link interview.rubikyt.com/r/{token} for people outside your workspace.

DELETE/v1/interviews/{id}/share

Revokes the share link immediately.

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.

bash
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.

Invite and share tokens
Tokens are bearer credentials. Rubi returns them once, on creation and on reissue. Never log them in plain text.