OneCompiler

AI practice interviews can run inside your own product. You keep your own screens
for browsing and picking interviews — our catalogue is available as an API — and
when a user starts one, you create the session server-side and open the interview
room in an iFrame. The room handles everything live: the interviewer's voice,
speech recognition, and the code editor with test cases for coding interviews.

This API uses the enterprise user model: you sync your application users with
POST /v1/users and authenticate them with their userApiToken. If you
haven't set that up yet, start with the Enterprise APIs section.

1. Read the interview catalogue

Render the catalogue however fits your product — your own cards, your own
filters. The response contains the tracks, the interviews per track, and the
interviewer personas.

curl 'https://api.onecompiler.com/v1/ai-interviewer/catalogue' \
--header 'X-API-Key: your_api_key'

Response (truncated):

{
  "status": "success",
  "personas": [ { "id": "maya", "name": "Maya", "title": "Supportive coach" } ],
  "tracks": [ { "id": "dsa", "cat": "technical", "name": "DSA / Problem solving" } ],
  "interviews": {
    "dsa": [
      {
        "id": "dsa-1",
        "title": "Arrays & hashing warm-up",
        "level": "Easy",
        "mins": 25,
        "kind": "code",
        "skills": ["Hash maps", "Two pointers"],
        "blurb": "Two classic problems with follow-ups on complexity.",
        "hasProblem": true
      }
    ]
  }
}

Interviews with "grades" (the K12 subjects) need a grade when the session is
created — show your user a grade picker first.

2. Create a session for your user

Call this from your backend when the user hits start. X-User-Token is the
api.token of the user copy you created via POST /v1/users.

curl --request POST 'https://api.onecompiler.com/v1/ai-interviewer/sessions' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token' \
--header 'Content-Type: application/json' \
--data '{
    "interviewId": "dsa-1",
    "personaId": "maya",
    "mode": "voice"
}'
Body fieldDescription
interviewIdRequired — an interview id from the catalogue, or the _id of a custom interview you created (section 6)
personaIdmaya (supportive coach), alex (neutral professional) or leo (bar raiser). Defaults to maya
modevoice or chat. Defaults to voice
gradeRequired for grade-adaptive interviews, e.g. "Grade 6" — one of the interview's grades
resumeOptional { "text": "...", "name": "..." } — the candidate's resume text; the interviewer tailors its questions to it
candidateContextOptional plain text about this candidate, up to 4,000 characters: current role, experience, what they've worked on. The interviewer uses it to pitch its questions and the report uses it to calibrate expectations. The candidate never sees it
skipResumeOptional. true skips the resume step in the room, so the candidate isn't asked to attach one. A resume you pass in this request still applies

If you already know who you're scheduling, pass it along. This is the usual
setup when your platform holds the candidate's profile:

curl --request POST 'https://api.onecompiler.com/v1/ai-interviewer/sessions' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token' \
--header 'Content-Type: application/json' \
--data '{
    "interviewId": "be-1",
    "personaId": "alex",
    "candidateContext": "Priya, backend developer with 4 years at a payments startup. Mostly Go and PostgreSQL. Applying for a senior role.",
    "skipResume": true
}'

Response:

{
  "status": "success",
  "session": { "_id": "44s2rmqbh", "interviewId": "dsa-1", "status": "active" },
  "embedUrl": "https://onecompiler.com/embed/ai-interviewer/44s2rmqbh"
}

Each session created consumes credits and counts toward the user's daily
interview quota (set by the plan you assign via PUT /v1/users/plan).

3. Embed the interview room

Open the room in an iFrame with the user's token. The allow attribute matters:
the room needs the microphone for voice answers and autoplay for the
interviewer's voice.

<iframe
  frameBorder="0"
  height="100%"
  width="100%"
  allow="microphone; autoplay"
  allowFullScreen
  src="https://onecompiler.com/embed/ai-interviewer/44s2rmqbh?userApiToken=users_api_token&interviewEvents=true"
></iframe>
Query ParameterDescription
userApiTokenRequired — the same user token the session was created for
apiKeyYour API account key (optional)
interviewEvents=truePost interview lifecycle events to the parent window

The room runs the full interview: on a fresh session it first shows the same
native preflight used on OneCompiler itself (mic behavior, interviewer voice,
and optional resume attach), then moves into the live room. The resume step is
left out when the session or the interview sets skipResume. Resumed sessions
skip that setup. After the user finishes, the room shows their score and a
short verdict — your application owns everything after that.

4. Capture interview events

With interviewEvents=true, the room posts messages to the parent window:

<script>
    window.onmessage = function (e) {
        if (e.data && e.data.source === "oc-interview") {
            console.log(e.data);
            // { source: "oc-interview", action: "interviewFinished",
            //   sessionId: "44s2rmqbh", score: 78 }
        }
    };
</script>
ActionWhen
interviewLoadedThe room is ready and the session has started
interviewFinishedThe user ended the interview and the report is ready (includes score)
interviewAlreadyCompletedThe session in the URL was already finished

5. Read the results

Pull the full report server-side once you receive interviewFinished (or by
polling). The response includes the overall score, verdict, strengths,
improvements, per-skill scores, and question-by-question feedback.

curl 'https://api.onecompiler.com/v1/ai-interviewer/sessions/44s2rmqbh' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token'

Response (truncated):

{
  "status": "success",
  "session": {
    "_id": "44s2rmqbh",
    "status": "completed",
    "score": 78,
    "feedback": {
      "score": 78,
      "verdict": "Strong problem solving; tighten complexity analysis.",
      "strengths": ["..."],
      "improvements": ["..."],
      "skills": [{ "name": "Hash maps", "score": 82 }],
      "questions": [{ "q": "...", "answer": "...", "score": 80 }]
    }
  }
}

6. Author your own interviews

You're not limited to the catalogue — create custom interviews with your own
role, topics, and interviewer playbook, then run sessions against them the same
way as catalogue interviews. The brief is private: it steers the AI interviewer and is
never shown to candidates.

curl --request POST 'https://api.onecompiler.com/v1/ai-interviewer/interviews' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token' \
--header 'Content-Type: application/json' \
--data '{
    "title": "Backend engineer screen — payments team",
    "kind": "talk",
    "level": "Medium",
    "mins": 30,
    "skills": ["APIs", "SQL", "Debugging"],
    "blurb": "A screening round for backend candidates.",
    "brief": "Interview for a mid-level backend role on a payments team. Cover REST API design, one SQL question on joins, and a debugging scenario with a failing webhook. Probe for reasoning, not memorized answers.",
    "status": "published"
}'

The response returns the interview with its _id. Create sessions against it
exactly like catalogue interviews, passing that _id as interviewId:

curl --request POST 'https://api.onecompiler.com/v1/ai-interviewer/sessions' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token' \
--header 'Content-Type: application/json' \
--data '{ "interviewId": "44xkq2m1p", "personaId": "alex" }'

For "kind": "code" include a problem object (language, title, body,
optional examples and starterCode) — the candidate gets the live editor.

FieldDescription
titleRequired, 3 to 120 characters
kindtalk (conversation) or code (live editor). Defaults to talk
levelEasy, Medium or Hard. Defaults to Medium
minsPlanned length, 5 to 120. Defaults to 30
skillsRequired, 1 to 6 short names. Each one is scored separately in the report
blurbOne line shown to candidates before they start
briefRequired, 20 to 6,000 characters. The private playbook the interviewer follows
problemRequired when kind is code. language is a OneCompiler language id such as python or mysql
questionsTotalOptional, 1 to 12. How many main questions to plan for; worked out from mins when left out
candidateContextOptional, up to 4,000 characters. Background that applies to everyone who takes this interview, such as "final-year CS students". Context passed when creating a session is added to it for that one candidate
skipResumeOptional. true skips the resume step for every session of this interview
statusdraft or published. Defaults to draft

Generate an interview from a description

If you'd rather not write the brief yourself, describe the interview in plain
English. We draft every field from your description and save the result as a
custom interview, the same way the "New interview" dialog on OneCompiler does.

curl --request POST 'https://api.onecompiler.com/v1/ai-interviewer/interviews/generate' \
--header 'X-API-Key: your_api_key' \
--header 'X-User-Token: users_api_token' \
--header 'Content-Type: application/json' \
--data '{
    "prompt": "A 40 minute live coding round for a mid-level backend engineer. Two questions on REST API design and caching, then have them write a Python function that merges overlapping intervals.",
    "status": "published"
}'

The response has the same shape as creating an interview with every field
filled in, including the drafted brief and, for coding interviews, a
problem with starter code:

{
  "status": "success",
  "interview": {
    "_id": "44xkq9w2r",
    "title": "Backend engineer: API design, caching and intervals",
    "kind": "code",
    "level": "Medium",
    "mins": 40,
    "skills": ["REST API design", "Caching", "Interval merging", "Complexity analysis"],
    "brief": "Open with a short overview, then ask one question at a time...",
    "problem": { "language": "python", "title": "Merge Overlapping Intervals", "body": "..." },
    "skipResume": false,
    "status": "published"
  }
}

Things to know:

  • prompt is required, 10 to 4,000 characters. Mention the role, the level,
    the topics, and whether the candidate should write code.
  • Any field from the table above that you send next to prompt wins over
    the drafted value. Use it to pin status, mins, candidateContext or
    skipResume, or to supply your own problem.
  • It's saved as a draft unless you pass "status": "published". Read it
    back or edit it with the endpoints below before sharing it.
  • The call takes around 10 seconds because a model writes the interview.
    Set your HTTP timeout to 60 seconds.
  • Each successful call uses 50 credits. If your project can't cover that, the
    call fails with E002: insufficient credits before anything is generated,
    and a failed generation isn't charged.
  • It also checks the user's daily interview quota, so a user who has used up
    their interviews for the day can't generate more until it resets.

Manage and score them with the rest of the surface:

EndpointDescription
POST /v1/ai-interviewer/interviews/generateCreate one from a plain-English prompt (see above)
GET /v1/ai-interviewer/interviewsList your custom interviews
GET /v1/ai-interviewer/interviews/:idRead one (includes the private brief and candidateContext)
PUT /v1/ai-interviewer/interviews/:idUpdate any field, e.g. {"status": "draft"} to unpublish
DELETE /v1/ai-interviewer/interviews/:idDelete (past sessions keep their reports)
GET /v1/ai-interviewer/interviews/:id/resultsEvery session taken against it, with taker name, status and score