# Eliciteer Backend API Documentation
Complete API reference for the Eliciteer AI-powered interview agent backend.
## Table of Contents
- [Overview](#overview)
- [Base URL](#base-url)
- [Authentication](#authentication)
- [Endpoints](#endpoints)
- [Health & Status](#health--status)
- [Topic Management](#topic-management)
- [Interview Management](#interview-management)
- [Interview Chat](#interview-chat)
- [System Prompt Generation](#system-prompt-generation)
- [Rating & Feedback](#rating--feedback)
- [Lead Capture](#lead-capture)
- [Webhooks](#webhooks)
- [OpenAI-Compatible API](#openai-compatible-api)
- [Data Models](#data-models)
- [Error Handling](#error-handling)
- [Examples](#examples)
---
## Overview
The Eliciteer Backend API provides endpoints for creating and managing AI-powered interview topics. The system uses LangGraph agents to conduct structured interviews based on briefings, collecting information through conversational interactions.
**Key Features:**
- Create interview topics from briefings
- Conduct AI-powered interviews with participants
- Track interview progress and collect information
- Generate system prompts automatically
- Submit ratings and feedback
- Webhook notifications on completion
- Transactional completion emails and marketing lead capture, both via Resend
---
## Base URL
**Production:** `https://your-backend.vercel.app`
**Development:** `http://localhost:8000`
All endpoints are relative to the base URL.
---
## Authentication
Authentication is **opt-in** and controlled by environment variables, so the
defaults preserve the open behavior while allowing you to lock down the public
SDK surface in production:
- **Topic creation API key** — set `ELICITEER_API_KEY` to require the matching
value in the `X-API-Key` header on `POST /topic`. Disabled when unset.
- **Per-topic apply token** — every topic is created with a public `apply_token`.
Set `ELICITEER_REQUIRE_APPLY_TOKEN=true` to require it when starting interviews
(`POST /topic/{id}/start`), passed via the `token` query parameter or the
`X-Eliciteer-Token` header. Disabled when unset (token is still returned).
- **Rate limiting** — set `ELICITEER_START_RATE_LIMIT` to the max number of
`POST /topic/{id}/start` calls allowed per client IP per minute (`0`/unset =
disabled). Excess requests get `429 Too Many Requests`.
### CORS
The published `eliciteer-chat-sdk` runs on customer domains and calls this API
directly, so cross-origin requests must be allowed. CORS is configurable via
environment (no need to hardcode every customer):
- `CORS_ALLOW_ORIGINS` — comma-separated list of exact origins to allow.
- `CORS_ALLOW_ORIGIN_REGEX` — regex matching allowed origins.
- `CORS_ALLOW_ALL_ORIGINS=true` — allow any origin (credentials are disabled in
this mode, per the CORS spec).
FastAPI answers `OPTIONS` preflight automatically once origins are allowed.
General recommendations:
- Use environment variables for sensitive configuration
- Use HTTPS in production
---
## Endpoints
### Health & Status
#### GET `/`
Check if the backend is running.
---
#### GET `/api-docs`
View the complete API documentation in a readable HTML format.
**Response:** HTML page with formatted API documentation
**Example:**
bash
# Open in browser:
https://your-backend.vercel.app/api-docs
**Note:** This endpoint renders the documentation with syntax highlighting and styling for easy reading in a web browser.
---
#### GET `/api-docs/raw`
Get the API documentation as raw Markdown.
**Response:** Plain text Markdown content
**Content-Type:** `text/markdown; charset=utf-8`
**Example:**
bash
curl https://your-backend.vercel.app/api-docs/raw
**Use Cases:**
- Programmatic access to documentation
- Rendering in other Markdown viewers
- Integration with documentation tools
---
#### GET `/docs`
FastAPI's interactive Swagger UI documentation (auto-generated from code).
**Example:**
bash
# Open in browser:
https://your-backend.vercel.app/docs
---
#### GET `/redoc`
FastAPI's ReDoc documentation (alternative to Swagger UI).
**Example:**
bash
# Open in browser:
https://your-backend.vercel.app/redoc
---
#### GET `/`
Check if the backend is running.
**Response:**
json
{
"message": "Eliciteer AI Backend is running",
"status": "ok",
"database": "connected" | "in-memory",
"python_version": "3.9.0"
}
**Example:**
bash
curl https://your-backend.vercel.app/
---
#### GET `/health`
Detailed health check endpoint that tests database connectivity.
**Response:**
json
{
"status": "ok",
"database": "connected and healthy" | "not configured" | "error: ",
"python_version": "3.9.0"
}
**Example:**
bash
curl https://your-backend.vercel.app/health
---
### Topic Management
#### POST `/topic`
Create a new interview topic from a briefing. A topic can be answered by multiple users, each getting their own interview session.
**Request Body:**
json
{
"text": "Find out the user's favorite programming language and why they like it",
"client_name": "Acme Corp",
"client_email": "contact@acme.com",
"notify_on_complete": true,
"webhook_url": "https://your-webhook.com/callback",
"system_prompt": "You are a friendly interviewer..."
}
**Request Fields:**
- `text` (string, required): The briefing describing what information to gather
- `client_name` (string, optional): Name of the client/organization
- `client_email` (string, optional): Email for completion notifications
- `notify_on_complete` (boolean, optional): Send email notification when interview completes (default: `false`)
- `webhook_url` (string, optional): URL to call when interview completes
- `system_prompt` (string, optional): Custom system prompt for the interviewer (auto-generated if not provided)
**Headers:**
- `X-API-Key` (string, optional): Required only when the server sets `ELICITEER_API_KEY`.
**Response:**
json
{
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"link": "https://your-frontend.com/interview/550e8400-e29b-41d4-a716-446655440000",
"apply_token": "kP3xY7...redacted"
}
- `apply_token` (string): Public per-topic token for starting interviews from the SDK. Enforced only when `ELICITEER_REQUIRE_APPLY_TOKEN=true`.
**Example:**
bash
curl -X POST https://your-backend.vercel.app/topic \
-H "Content-Type: application/json" \
-d '{
"text": "Find out the user's favorite programming language",
"client_name": "Tech Corp",
"notify_on_complete": true
}'
**Status Codes:**
- `200`: Topic created successfully
- `500`: Server error
---
#### POST `/topic/{topic_id}/start`
Start a new interview session for a topic. Each call creates a new interview session that can be answered independently.
**Path Parameters:**
- `topic_id` (string): The unique topic identifier
**Request Body:**
json
{
"participant_name": "John Doe",
"participant_email": "john@example.com",
"context": "Job posting: Senior Python Engineer. Requires 5+ years Python, FastAPI."
}
**Request Fields:**
- `participant_name` (string, optional): Name of the participant
- `participant_email` (string, optional): Email of the participant
- `context` (string, optional): **Ad-hoc per-session context** (e.g. a job description). Saved on the interview and used by the AI on every turn, so one generic topic/briefing can serve many tailored sessions. Returned by `GET /interview/{id}`.
**Headers / Query (optional, token enforcement):**
- `X-Eliciteer-Token` header or `?token=` query parameter: the topic's `apply_token`. Required only when the server sets `ELICITEER_REQUIRE_APPLY_TOKEN=true`.
**Response:**
json
{
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"link": "https://your-frontend.com/interview/660e8400-e29b-41d4-a716-446655440001"
}
**Example:**
bash
curl -X POST https://your-backend.vercel.app/topic/550e8400-e29b-41d4-a716-446655440000/start \
-H "Content-Type: application/json" \
-d '{
"participant_name": "John Doe",
"context": "Job posting: Senior Python Engineer..."
}'
**Status Codes:**
- `200`: Interview session created successfully
- `403`: Missing/invalid apply token (when enforcement is enabled)
- `404`: Topic not found
- `429`: Too many requests (when rate limiting is enabled)
- `500`: Server error
---
#### PATCH `/topic/{topic_id}`
Update a topic's system prompt. This affects all future interview sessions for this topic.
**Path Parameters:**
- `topic_id` (string): The unique topic identifier
**Request Body:**
json
{
"system_prompt": "You are a professional interviewer. Be concise and direct."
}
**Response:**
json
{
"status": "updated"
}
**Example:**
bash
curl -X PATCH https://your-backend.vercel.app/topic/550e8400-e29b-41d4-a716-446655440000 \
-H "Content-Type: application/json" \
-d '{
"system_prompt": "You are a professional interviewer."
}'
**Status Codes:**
- `200`: Topic updated successfully
- `404`: Topic not found
---
### Interview Management
#### GET `/interview/{interview_id}`
Retrieve interview session details and current state.
**Path Parameters:**
- `interview_id` (string): The unique interview identifier
**Response:**
json
{
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"briefing": "Find out the user's favorite programming language",
"client_name": "Tech Corp",
"client_email": "contact@techcorp.com",
"notify_on_complete": true,
"webhook_url": "https://webhook.example.com/callback",
"system_prompt": "You are a friendly interviewer...",
"status": "in_progress" | "completed",
"messages": [
{
"role": "user",
"content": "Hello"
},
{
"role": "assistant",
"content": "Hi! Let's start..."
}
],
"plan": [
{
"topic": "Favorite Language",
"description": "What programming language they prefer",
"status": "completed"
}
],
"current_topic_index": 1,
"collected_info": "- User prefers Python\n- Likes it for readability",
"interview_summary": "User's Programming Language Preferences",
"context": "Job posting: Senior Python Engineer...",
"assessment": null,
"participant_name": "John Doe",
"participant_email": "john@example.com",
"notification_sent": false,
"rating": 5,
"feedback": "Great experience!",
"created_at": "2024-01-15T10:00:00Z",
"completed_at": "2024-01-15T10:30:00Z"
}
**Example:**
bash
curl https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001
**Status Codes:**
- `200`: Interview found
- `404`: Interview not found
---
#### GET `/interview/{interview_id}/collected-info`
Technical endpoint for external systems to retrieve collected information from an interview. Returns only the essential information collected during the interview, along with metadata.
**Path Parameters:**
- `interview_id` (string): The unique interview identifier
**Response:**
json
{
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"collected_info": "- User prefers Python\n- Likes it for readability\n- Uses it for data science",
"interview_summary": "User's Programming Language Preferences",
"completed_at": "2024-01-15T10:30:00Z",
"created_at": "2024-01-15T10:00:00Z"
}
**Response Fields:**
- `interview_id` (string): Unique interview identifier
- `topic_id` (string): The topic this interview belongs to
- `status` (string): Interview status (`"in_progress"` or `"completed"`)
- `collected_info` (string): Information collected during the interview
- `interview_summary` (string|null): Summary title when complete
- `completed_at` (string|null): ISO timestamp when interview was completed
- `created_at` (string): ISO timestamp when interview was created
**Example:**
bash
curl https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/collected-info
**Use Cases:**
- Integration with requirement management systems
- Data export and reporting
- Automated processing of interview results
- Webhook alternative for simpler integrations
**Status Codes:**
- `200`: Collected information retrieved successfully
- `400`: Invalid request (e.g., topic_id used instead of interview_id)
- `404`: Interview not found
---
### Interview Chat
#### POST `/interview/{interview_id}/chat`
Send a message in an interview session and receive the AI agent's response.
**Path Parameters:**
- `interview_id` (string): The unique interview identifier
**Request Body:**
json
{
"message": "I really like Python because it's easy to read",
"debug": false
}
**Request Fields:**
- `message` (string, required): The user's message/response
- `debug` (boolean, optional): Include debug information in response (default: `false`)
**Response:**
json
{
"response": "That's great! What specific features of Python do you find most appealing?",
"status": "continue" | "completed",
"is_complete": false,
"interview_summary": null,
"assessment": null,
"current_topic_index": 1,
"total_topics": 3,
"ui_options": {
"type": "text" | "boolean",
"options": ["Yes", "No"] | null
},
"debug_info": {
"plan": [...],
"collected_info": "...",
"analysis_result": {...},
"system_prompt": "...",
"briefing": "..."
}
}
**Response Fields:**
- `response` (string): The AI agent's response/question
- `status` (string): Interview status (`"continue"` or `"completed"`)
- `is_complete` (boolean): Whether the interview is complete
- `interview_summary` (string|null): Summary title when interview is complete
- `assessment` (object|null): Optional briefing-driven verdict (e.g. a screening decision). `null` unless the briefing asked for a judgment. See [Assessment](#assessment).
- `current_topic_index` (integer): Current topic index (0-based)
- `total_topics` (integer): Total number of topics in the plan
- `ui_options` (object|null): UI configuration for the question
- `type`: `"text"` for text input or `"boolean"` for yes/no
- `options`: Array of options for boolean questions (e.g., `["Yes", "No"]`)
- `debug_info` (object): Only included if `debug: true` in request
**Example:**
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/chat \
-H "Content-Type: application/json" \
-d '{
"message": "I like Python",
"debug": false
}'
**Status Codes:**
- `200`: Message processed successfully
- `404`: Interview not found
- `500`: Server error
**Notes:**
- The first message in an interview triggers the planning phase
- The agent automatically moves through topics based on responses
- When `is_complete` is `true`, the interview has finished
- If `notify_on_complete` was set and `client_email` provided, an email notification is sent
- If `webhook_url` was set, a webhook is triggered with completion data. The webhook is delivered **after** the chat response has been sent (as a background task), so a slow or unreachable webhook receiver never delays the participant. Delivery timeout is 10 seconds; failures are logged and not retried.
---
#### POST `/interview/{interview_id}/chat/stream`
Streaming variant of the chat endpoint. Identical request body and side effects
(state updates, usage metering, notifications, webhooks), but the AI's reply is
delivered incrementally as **Server-Sent Events** so the participant sees the
question appear as it is generated.
**Request Body:** same as `POST /interview/{interview_id}/chat`.
**Response:** `Content-Type: text/event-stream` with the following events:
| Event | Payload | Meaning |
|-------|---------|---------|
| `token` | `{"text": "..."}` | A piece of the AI's reply, in order. Zero or more. |
| `done` | Same JSON object as the non-streaming endpoint's response body | Emitted exactly once, after the reply is complete and state is persisted. |
| `error` | `{"detail": "...", "status_code": 500}` | Emitted instead of `done` if generation fails mid-stream (HTTP status is already 200 by then). |
event: token
data: {"text": "Which programming"}
event: token
data: {"text": " language do you prefer?"}
event: done
data: {"response": "Which programming language do you prefer?", "status": "continue", "is_complete": false, "interview_summary": null, "assessment": null, "current_topic_index": 0, "total_topics": 2, "ui_options": {"type": "text", "options": null}}
**Example:**
bash
curl -N -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/chat/stream \
-H "Content-Type: application/json" \
-d '{"message": "I like Python"}'
**Status Codes:**
- `200`: Stream opened (errors after this point arrive as an `error` event)
- `400`: ID belongs to a topic, or the interview is already completed
- `404`: Interview not found
**Notes:**
- Validation errors (unknown ID, completed interview) are raised as normal HTTP errors before the stream starts.
- On the final turn, the thank-you message streams while the summary and optional assessment are generated concurrently.
- The `eliciteer-chat-sdk` exposes this endpoint via `client.sendMessageStream(interviewId, message, { onToken })`.
---
### System Prompt Generation
#### POST `/generate-prompt`
Generate a custom system prompt based on a briefing.
**Request Body:**
json
{
"briefing": "Find out the user's favorite programming language and why they like it"
}
**Response:**
json
{
"system_prompt": "You are an expert interviewer conducting a research session. Your goal is to gather information about the participant's favorite programming language and their reasons for preferring it. Ask probing questions to understand their preferences, experiences, and specific features they value. Be professional, friendly, and conversational. Ask only one question at a time."
}
**Example:**
bash
curl -X POST https://your-backend.vercel.app/generate-prompt \
-H "Content-Type: application/json" \
-d '{
"briefing": "Find out the user's favorite programming language"
}'
**Status Codes:**
- `200`: Prompt generated successfully
- `500`: Server error
---
### Rating & Feedback
#### POST `/interview/{interview_id}/rating`
Submit a rating and feedback for a completed interview.
**Path Parameters:**
- `interview_id` (string): The unique interview identifier
**Request Body:**
json
{
"rating": 5,
"feedback": "Great interview experience! The questions were relevant and the flow was smooth."
}
**Request Fields:**
- `rating` (integer, required): Rating from 1 to 5 stars
- `feedback` (string, optional): Text feedback
**Response:**
json
{
"status": "success",
"message": "Thank you for your feedback!"
}
**Example:**
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/rating \
-H "Content-Type: application/json" \
-d '{
"rating": 5,
"feedback": "Great experience!"
}'
**Status Codes:**
- `200`: Rating submitted successfully
- `400`: Invalid rating (must be 1-5)
- `404`: Interview not found
---
### Lead Capture
#### POST `/leads`
Capture an email address from the marketing site (e.g. the landing page) for retargeting. Upserts the address into the `leads` table and syncs it to the Resend Audience configured via `RESEND_AUDIENCE_ID`. Not linked to a topic or interview.
**Request Body:**
json
{
"email": "visitor@example.com",
"source": "landing_final_cta"
}
**Request Fields:**
- `email` (string, required): Address to subscribe
- `source` (string, optional): Where the lead was captured, e.g. `landing_final_cta`
**Response:**
json
{
"status": "subscribed"
}
`status` is `"already_subscribed"` if the email was already an active lead.
**Example:**
bash
curl -X POST https://your-backend.vercel.app/leads \
-H "Content-Type: application/json" \
-d '{"email": "visitor@example.com", "source": "landing_final_cta"}'
**Status Codes:**
- `200`: Lead captured
- `400`: Invalid email address
- `429`: Too many requests (rate limited per IP; default 5/min, see `ELICITEER_LEADS_RATE_LIMIT`)
---
### Webhooks
#### POST `/webhooks/resend`
Receives delivery/bounce/complaint/unsubscribe events from Resend (signed via [Svix](https://www.svix.com/)) and updates local state: `email_events.status` for delivery tracking, and `leads.subscribed` when a contact unsubscribes. Configure this URL as the endpoint in the Resend dashboard, and set `RESEND_WEBHOOK_SECRET` to the signing secret shown there. Requests with an invalid or missing signature are rejected with `401`.
This endpoint is for Resend to call, not for direct client use.
---
## Data Models
### BriefingRequest
typescript
{
text: string; // Required: Briefing text
client_name?: string; // Optional: Client name
client_email?: string; // Optional: Client email
notify_on_complete?: boolean; // Optional: Send email on completion
webhook_url?: string; // Optional: Webhook URL
system_prompt?: string; // Optional: Custom system prompt
}
### TopicResponse
typescript
{
topic_id: string; // UUID of the topic
link: string; // Frontend interview link (users can start interviews from this)
apply_token?: string; // Public per-topic token for starting interviews from the SDK
}
### StartInterviewRequest
typescript
{
participant_name?: string; // Optional: participant name
participant_email?: string; // Optional: participant email
context?: string; // Optional: ad-hoc per-session context (e.g. a job description)
}
### StartInterviewResponse
typescript
{
interview_id: string; // UUID of the interview session
topic_id: string; // UUID of the topic this interview belongs to
link: string; // Frontend interview link
}
### Assessment
typescript
{
applicable: boolean; // true only if the briefing requested a judgment
verdict?: string | null; // e.g. "qualified" / "not qualified"
score?: number | null; // optional 0.0–1.0
reasoning?: string | null; // concise justification
}
### ChatRequest
typescript
{
message: string; // Required: User's message
debug?: boolean; // Optional: Include debug info
}
### RatingRequest
typescript
{
rating: number; // Required: 1-5 stars
feedback?: string; // Optional: Text feedback
}
### LeadRequest
typescript
{
email: string; // Required: address to subscribe
source?: string; // Optional: capture source, e.g. "landing_final_cta"
}
### LeadResponse
typescript
{
status: "subscribed" | "already_subscribed";
}
### Interview State
typescript
{
interview_id: string;
topic_id: string;
briefing: string;
client_name?: string;
client_email?: string;
notify_on_complete: boolean;
webhook_url?: string;
system_prompt?: string;
status: "in_progress" | "completed";
messages: Array<{
role: "user" | "assistant";
content: string;
}>;
plan: Array<{
topic: string;
description: string;
status: "pending" | "in_progress" | "completed";
}>;
current_topic_index: number;
collected_info: string;
interview_summary?: string;
context?: string; // Ad-hoc per-session context supplied at start
assessment?: object | null; // Optional briefing-driven verdict (when complete)
participant_name?: string;
participant_email?: string;
notification_sent: boolean;
rating?: number;
feedback?: string;
rated_at?: string;
created_at: string;
completed_at?: string;
}
---
## Error Handling
The API uses standard HTTP status codes:
| Status Code | Meaning | Description |
|------------|---------|-------------|
| `200` | OK | Request successful |
| `400` | Bad Request | Invalid request parameters |
| `404` | Not Found | Resource not found |
| `500` | Internal Server Error | Server error occurred |
**Error Response Format:**
json
{
"detail": "Error message describing what went wrong"
}
**Example Error Response:**
json
{
"detail": "Interview not found"
}
---
## Examples
### Complete Interview Flow
#### 1. Create a Topic
bash
curl -X POST https://your-backend.vercel.app/topic \
-H "Content-Type: application/json" \
-d '{
"text": "Find out the user's favorite programming language and why",
"client_name": "Tech Corp",
"notify_on_complete": true,
"client_email": "contact@techcorp.com"
}'
**Response:**
json
{
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"link": "https://your-frontend.com/interview/550e8400-e29b-41d4-a716-446655440000"
}
#### 2. Start an Interview Session
bash
curl -X POST https://your-backend.vercel.app/topic/550e8400-e29b-41d4-a716-446655440000/start \
-H "Content-Type: application/json" \
-d '{
"participant_name": "John Doe"
}'
**Response:**
json
{
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"link": "https://your-frontend.com/interview/660e8400-e29b-41d4-a716-446655440001"
}
#### 3. Start the Interview (First Message)
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/chat \
-H "Content-Type: application/json" \
-d '{
"message": "Hello, I'm ready to start"
}'
**Response:**
json
{
"response": "Hello! I'd like to learn about your programming language preferences. What programming language do you use most often?",
"status": "continue",
"is_complete": false,
"current_topic_index": 0,
"total_topics": 2,
"ui_options": {
"type": "text",
"options": null
}
}
#### 4. Continue the Conversation
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/chat \
-H "Content-Type: application/json" \
-d '{
"message": "I primarily use Python"
}'
**Response:**
json
{
"response": "That's great! What do you like most about Python?",
"status": "continue",
"is_complete": false,
"current_topic_index": 0,
"total_topics": 2
}
#### 5. Complete the Interview
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/chat \
-H "Content-Type: application/json" \
-d '{
"message": "I love Python because of its readability and extensive libraries"
}'
**Response:**
json
{
"response": "Thank you for sharing! I have all the information I need. Your feedback about Python's readability and libraries has been noted.",
"status": "completed",
"is_complete": true,
"interview_summary": "User's Programming Language Preferences",
"current_topic_index": 2,
"total_topics": 2
}
#### 6. Submit Rating
bash
curl -X POST https://your-backend.vercel.app/interview/660e8400-e29b-41d4-a716-446655440001/rating \
-H "Content-Type: application/json" \
-d '{
"rating": 5,
"feedback": "Great interview experience!"
}'
---
### Webhook Payload
When an interview completes and a `webhook_url` is configured, the following payload is sent:
json
{
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"topic_id": "550e8400-e29b-41d4-a716-446655440000",
"client_name": "Tech Corp",
"interview_summary": "User's Programming Language Preferences",
"collected_info": "- User primarily uses Python\n- Likes readability and libraries",
"assessment": null,
"completed_at": "2024-01-15T10:30:00Z"
}
`assessment` is `null` for plain information-gathering interviews. When the
briefing asked for a judgment (e.g. a job-screening briefing), it is an object
like `{ "applicable": true, "verdict": "qualified", "score": 0.82, "reasoning": "..." }`.
---
## Rate Limits
Two endpoints have built-in per-IP rate limiting; everything else is unlimited:
- `POST /topic/{id}/start` — opt-in via `ELICITEER_START_RATE_LIMIT` (disabled unless set)
- `POST /leads` — on by default at 5/minute; configurable via `ELICITEER_LEADS_RATE_LIMIT` (`0` disables)
Excess requests get `429 Too Many Requests`. For production deployments, consider adding rate limiting to the remaining endpoints as well (per IP and/or per API key).
---
## OpenAI-Compatible API
### POST `/v1/chat/completions`
OpenAI-compatible chat completions endpoint for integrating interviews into any chat frontend that supports OpenAI's API format.
**Path Parameters:** None
**Headers:**
- `X-Interview-ID` (optional): Interview ID for the session. Can also be provided in the request body.
**Request Body:**
json
{
"model": "gpt-4",
"messages": [
{
"role": "user",
"content": "I really like Python because it's easy to read"
}
],
"interview_id": "660e8400-e29b-41d4-a716-446655440001",
"temperature": 0.7
}
**Request Fields:**
- `model` (string, optional): Model name for compatibility (default: `"gpt-4"`, not used)
- `messages` (array, required): Array of message objects with `role` ("system", "user", "assistant") and `content`
- `interview_id` (string, optional): Interview ID (can also be passed via `X-Interview-ID` header)
- `campaign_id` (string, optional): [DEPRECATED] Use `interview_id` instead. Kept for backward compatibility.
- `temperature` (float, optional): Temperature for compatibility (not used)
- `max_tokens` (integer, optional): Max tokens for compatibility (not used)
- `stream` (boolean, optional): Streaming not yet supported
**Response:**
json
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "That's great! What specific features of Python do you find most appealing?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
},
"interview_status": "continue",
"is_complete": false,
"interview_summary": null,
"current_topic_index": 1,
"total_topics": 3
}
**Response Fields:**
- Standard OpenAI fields: `id`, `object`, `created`, `model`, `choices`, `usage`
- Additional interview fields:
- `interview_status` (string): `"continue"` or `"completed"`
- `is_complete` (boolean): Whether the interview is complete
- `interview_summary` (string|null): Summary title when complete
- `current_topic_index` (integer): Current topic index (0-based)
- `total_topics` (integer): Total number of topics
**Example:**
bash
curl -X POST https://your-backend.vercel.app/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-Interview-ID: 660e8400-e29b-41d4-a716-446655440001" \
-d '{
"model": "gpt-4",
"messages": [
{"role": "user", "content": "I like Python"}
]
}'
**Using with OpenAI SDK:**
python
import openai
# Configure the client to use your backend
client = openai.OpenAI(
api_key="dummy", # Not used, but required
base_url="https://your-backend.vercel.app/v1"
)
# Make a chat completion request
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "user", "content": "I like Python"}
],
extra_headers={
"X-Interview-ID": "660e8400-e29b-41d4-a716-446655440001"
}
)
print(response.choices[0].message.content)
print(f"Interview complete: {response.is_complete}")
**Status Codes:**
- `200`: Chat completion successful
- `400`: Bad request (missing interview_id or invalid messages)
- `404`: Interview not found
- `500`: Server error
**Notes:**
- The endpoint follows OpenAI's API format exactly, making it compatible with any OpenAI client library
- Interview ID can be provided via `X-Interview-ID` header or in the request body
- The `messages` array should contain the full conversation history
- Additional interview metadata is included in the response for tracking progress
- Token usage is estimated (1 token ≈ 4 characters)
---
## Versioning
The current API version is **v1** (implicit). Future versions may be introduced with version prefixes (e.g., `/v2/topic`).
---
## Support
For issues, questions, or contributions:
- Check the [README](../README.md) for setup instructions
- Review the [deployment guide](../DEPLOYMENT.md) for deployment information
- Open an issue on the repository
---
**Last Updated:** January 2024