AI Service API
The AI Service GraphQL API powers all artificial intelligence and machine learning operations on the AIQLick platform. Built with FastAPI and Strawberry GraphQL, it specializes in real-time streaming of AI processing progress through GraphQL subscriptions.
Endpoint: https://ai.aiqlick.com/graphql (production) | https://ai-dev.aiqlick.com/graphql (development)
Authentication
The AI Service validates the same JWT tokens issued by the Backend. For HTTP requests, include the token in the Authorization header. For WebSocket subscriptions, pass the token in connectionParams:
{
"connectionParams": {
"token": "<jwt_token>"
}
}
Subscriptions
The AI Service provides 12 GraphQL subscriptions that stream real-time progress as AI operations execute. Each subscription emits typed events so the frontend can display live feedback to users.
CV Extraction
Parses uploaded CV documents into structured data fields (name, email, experience, education, skills, etc.). The union also includes a CVExtractionPartial variant that streams as each of the 5 parallel extraction schemas lands plus the pre-flight classifier verdict (step="classification"). See CV & Job Extraction for the architectural detail.
subscription {
extractCv(input: { file_url: "...", id: "...", sequential: true, company_id: "...", user_id: "..." }) {
... on CVExtractionProcessing {
percentage
message
}
... on CVExtractionPartial {
step # "contact" | "skills" | "education" | "experience" | "metadata" | "classification"
partialJson # JSON-encoded slice — frontend JSON.parse + merges into form state
}
... on CVExtractionSuccess {
parsedCv {
id
fields
}
}
... on CVExtractionFailure {
code
message
}
}
}
Job Parsing
Parses job descriptions into structured fields (title, requirements, responsibilities, qualifications). Mirrors the CV pattern: the union includes a JobParsingPartial variant that streams as each of the 4 converged extraction steps lands (core_info, requirements_qualifications, responsibilities_skills, compensation_benefits) plus the pre-flight classifier verdict (step="classification").
subscription {
parseJob(input: { jobId: "...", companyId: "..." }) {
... on JobParsingProcessing {
percentage
message
}
... on JobParsingPartial {
step # "core_info" | "requirements_qualifications" | "responsibilities_skills" | "compensation_benefits" | "classification"
partialJson
}
... on JobParsingSuccess {
parsedJob {
id
fields
}
}
... on JobParsingFailure {
code
message
}
}
}
Face Extraction
Detects and extracts face images from CV documents using AWS Rekognition.
subscription {
faceExtraction(input: { cvId: "...", userId: "..." }) {
... on FaceExtractionProcessing {
percentage
message
}
... on FaceExtractionSuccess {
faceUrl
}
... on FaceExtractionFailure {
code
message
}
}
}
Add Candidate
Executes the full candidate onboarding pipeline: CV extraction, face detection, data validation, and candidate record creation.
subscription {
addCandidate(input: { cvId: "...", jobId: "...", companyId: "..." }) {
... on AddCandidateProcessing {
percentage
stage
message
}
... on AddCandidateSuccess {
candidate {
id
status
}
}
... on AddCandidateFailure {
code
message
}
}
}
Job Matching
Two matching subscriptions calculate compatibility scores between profiles and jobs.
User-Job Matching scores a user profile against a job posting:
subscription {
userJobMatching(input: { userId: "...", jobId: "...", companyId: "..." }) {
... on UserJobMatchingProcessing {
percentage
message
}
... on UserJobMatchingSuccess {
score
breakdown
}
... on UserJobMatchingFailure {
code
message
}
}
}
Candidate-Job Matching scores an existing candidate against their assigned job:
subscription {
candidateJobMatching(input: { candidateId: "...", companyId: "..." }) {
... on CandidateJobMatchingProcessing {
percentage
message
}
... on CandidateJobMatchingSuccess {
score
breakdown
}
... on CandidateJobMatchingFailure {
code
message
}
}
}
Basic Matching
Performs simple skill-based matching without the full AI scoring pipeline.
subscription {
basicMatching(input: { talentId: "...", jobId: "..." }) {
... on BasicMatchingProcessing {
percentage
}
... on BasicMatchingSuccess {
score
matchedSkills
}
... on BasicMatchingFailure {
code
message
}
}
}
Text Rewrite
Rewrites text content using AI, useful for improving job descriptions, summaries, and profiles.
subscription {
textRewrite(input: { text: "...", style: "professional", companyId: "..." }) {
... on TextRewriteProcessing {
percentage
}
... on TextRewriteSuccess {
rewrittenText
}
... on TextRewriteFailure {
code
message
}
}
}
Meeting Insight
Generates AI-powered analysis of meeting transcripts, including summaries, action items, and participant assessments. Supports versioning for live updates during ongoing meetings.
subscription {
generateMeetingInsight(input: { meetingId: "...", companyId: "..." }) {
... on MeetingInsightProcessing {
percentage
message
}
... on MeetingInsightSuccess {
insight {
id
summary
actionItems
version
}
}
... on MeetingInsightFailure {
code
message
}
}
}
Agent Chat
Streams AI agent responses in real-time. This subscription emits a sequence of typed events as the agent processes the user's message, executes tools, and generates a response.
subscription {
agentChat(input: { agentId: "...", conversationId: "...", message: "..." }) {
... on ChatProcessing {
message
}
... on ChatContextLoaded {
documentCount
tokenCount
}
... on ChatChunk {
content
index
}
... on ChatReasoningChunk {
delta
chunkIndex
}
... on ChatToolCall {
toolName
arguments
}
... on ChatToolResult {
toolName
result
}
... on ChatComplete {
fullResponse
usage {
inputTokens
outputTokens
creditCost
}
}
... on ChatError {
code
message
}
}
}
Event sequence: ChatProcessing --> ChatContextLoaded --> ChatReasoningChunk (repeated, only when the agent's model supports extended thinking) --> ChatChunk (repeated) --> ChatToolCall / ChatToolResult (optional, repeated) --> ChatComplete or ChatError.
The subscription handler dedupes three event classes per turn so Bedrock's multi-hop tool loop cannot re-emit the same content:
ChatChunk— deduped bychunk_indexChatToolCall— deduped bytool_call_idChatToolResult— deduped bytool_call_id
Clients can therefore treat each event as the definitive version without needing their own idempotency layer.
ChatReasoningChunk carries the model's extended-thinking deltas (Claude Sonnet 4.x / Opus 4.x). Render in a separate "Reasoning" surface — never concatenate into the final response. Clients that omit the inline fragment will receive the events with all fields undefined and end up rendering empty/NaN blocks. See AI Agents → Reasoning Streaming.
ChatError codes
When ChatError is yielded, the code field is one of the values below — clients should special-case the billing/auth/attachment codes for targeted recovery hints, and fall through to a generic "try again" message for the rest.
| Code | When | What clients should do |
|---|---|---|
CONVERSATION_NOT_FOUND | The conversation id was deleted between subscribe and stream | Start a new conversation |
CONVERSATION_INACTIVE | Conversation is archived | Reactivate or start a new one |
UNAUTHORIZED | JWT missing/invalid OR conversation belongs to a different user/company | Re-auth, then retry |
RATE_LIMITED | Per-agent maxMessagesPerMinute exceeded | Wait and retry |
TOKEN_LIMIT_EXCEEDED | Per-agent maxTokensPerDay exhausted | Wait until reset or raise the limit |
INSUFFICIENT_CREDITS | Pre-check failed at billing | Show the credits-purchase flow |
SUBSCRIPTION_INACTIVE | Plan not ACTIVE/TRIALING | Show the activate-subscription flow |
PLAN_LIMIT_EXCEEDED | Operation count exceeded plan cap | Show the upgrade-plan flow |
ATTACHMENT_FAILED | A user-provided attachment couldn't be downloaded from S3 or its actual bytes exceed the size limit. Surfaced BEFORE the LLM call so no user/assistant rows are created. | Restore pendingAttachments from a snapshot so the user can re-upload without losing their selections — see Attachment retry UX |
CHAT_ERROR | Generic LLM/processing failure | Retry the message |
TOOL_ERROR | Tool execution failed | Check tool configuration |
System Monitoring
Two subscriptions provide system-level observability.
Task Subscription streams task execution events:
subscription {
taskSubscription(taskId: "...") {
status
progress
result
error
}
}
Metrics Subscription streams periodic system metrics:
subscription {
metricsSubscription {
activeWorkers
queueDepth
processingRate
errorRate
}
}
Subscription Reference
| Subscription | Purpose | Progress Type | Billing |
|---|---|---|---|
extractCv | CV parsing with structured data extraction | Percentage | Credits consumed |
parseJob | Job description parsing | Percentage | Credits consumed |
faceExtraction | Face detection from CV photos | Percentage | Credits consumed |
addCandidate | Full candidate onboarding pipeline | Percentage + stage | Credits consumed |
userJobMatching | User-job match scoring | Percentage | Credits consumed |
candidateJobMatching | Candidate-job matching | Percentage | Credits consumed |
basicMatching | Simple skill matching | Percentage | Credits consumed |
textRewrite | AI text rewriting | Percentage | Credits consumed |
generateMeetingInsight | Meeting analysis generation | Percentage | Credits consumed |
agentChat | Streaming AI agent chat | Chunked events | Credits consumed |
taskSubscription | System task monitoring | Event-based | None |
metricsSubscription | System metrics | Periodic | None |
Error Types
All subscriptions can emit error events. The error types follow a consistent structure:
| Error Code | Description |
|---|---|
VALIDATION_ERROR | Invalid input parameters or missing required fields |
PROCESSING_ERROR | Failure during AI model invocation or data processing |
TIMEOUT_ERROR | Operation exceeded the maximum allowed processing time |
BILLING_ERROR | Insufficient credits or inactive subscription |
Error events include a code field and a human-readable message field:
{
"code": "BILLING_ERROR",
"message": "Insufficient credit balance. Required: 5 credits, available: 2 credits."
}
Billing Integration
All AI subscriptions (except system monitoring) consume credits. The AI Service uses a BillingGate that:
- Pre-checks the user's subscription status and credit balance before starting the operation.
- Executes the AI operation (LLM invocation, image processing, etc.).
- Consumes credits based on actual token usage after completion.
Credit routing depends on the user's view mode:
- Employer mode (with
selectedCompanyId): Credits are deducted from the company balance. - Job Seeker mode: Credits are deducted from the user's personal balance.
Each operation is logged in the AIOperationLog table with token counts and credit cost for audit purposes.