Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tech-dipesh/yeti-Jobs/llms.txt

Use this file to discover all available pages before exploring further.

When you upload a resume to Yeti Jobs, it doesn’t just get stored — it gets read. The platform extracts the full text from your PDF using pdf-parse, sends it to a Groq-hosted AI model with a structured prompt, and returns a numeric ATS (Applicant Tracking System) compatibility score alongside a set of concrete improvement suggestions. The score and feedback are persisted in the ats_scores table and linked back to your user account so you can retrieve them at any time without re-uploading.

How the Scoring Pipeline Works

1

Upload your resume PDF

Send a multipart/form-data POST request to the resume endpoint with your PDF attached under the resume field. The server validates the file is present before proceeding.
curl -X POST https://yeti-jobs.onrender.com/api/v1/users/resume \
  -H 'Cookie: token=<your_jwt_token>' \
  -F 'resume=@/path/to/your-resume.pdf'
2

Text extraction via pdf-parse

The backend instantiates a PDFParse parser with the raw file buffer and calls getText(). This extracts all readable text from your PDF without requiring a file to be written to disk, keeping the operation fully in-memory.
3

AI analysis via Groq API

The extracted text is passed to the gemini utility (backend/src/utils/grok.js), which calls the Groq API using an OpenAI-compatible client. The call uses client.responses.create with model "openai/gpt-oss-20b" against base URL https://api.groq.com/openai/v1. The prompt instructs the model to return only a raw JSON object — no markdown, no code fences, no explanatory prose — with exactly two keys: ats_scores and feedback.The environment variable GROK_API must be set to a valid Groq API key for this step to succeed.
4

Parallel storage operations

Using Promise.all, the backend simultaneously:
  • Uploads the PDF to Supabase Storage (resume bucket) and gets the public URL.
  • Inserts a new row into ats_scores with the score (integer from ats_scores key) and feedback (JSONB array).
  • Updates the user’s resume_url column in the users table.
If any prior resume exists, the old Supabase object is deleted and the previous ats_scores row is removed before the new data is written. All writes are wrapped in a database transaction (BEGIN / COMMIT / ROLLBACK).

Upload Endpoint

POST /api/v1/users/resume
The request must be multipart/form-data. The file field name must be resume.
curl -X POST https://yeti-jobs.onrender.com/api/v1/users/resume \
  -H 'Cookie: token=<your_jwt_token>' \
  -F 'resume=@/Users/alex/Documents/alex-resume-2025.pdf'
On success the API responds with 201 Created:
{
  "message": "Resume Uploaded Successfully"
}

Retrieving Your Score

Fetch your most recent resume URL and ATS analysis result. The query joins ats_scores with users and returns only the latest record ordered by created_at DESC.
GET /api/v1/users/resume
curl https://yeti-jobs.onrender.com/api/v1/users/resume \
  -H 'Cookie: token=<your_jwt_token>'

Response Format

The API returns the data stored in the ats_scores table, joined with the resume_url from users:
{
  "message": {
    "user_id": "b7e1a2f3-0000-4cde-9876-000000000099",
    "created_at": "2025-07-10T14:22:05.000Z",
    "score": 72,
    "feedback": [
      "Add quantifiable achievements to work experience",
      "Include relevant keywords matching the job description",
      "Improve the skills section formatting"
    ],
    "resume_url": "https://<supabase-project>.supabase.co/storage/v1/object/public/resume/upload/<uuid>-resume.pdf"
  }
}
FieldTypeDescription
scoreinteger (0–100)ATS compatibility score. Higher is better.
feedbackstring arrayOrdered list of actionable improvement points.
resume_urlstringPublic URL to your uploaded PDF in Supabase Storage.
created_attimestampWhen this analysis was performed.

Database Schema

Scores are stored in the ats_scores table:
CREATE TABLE ats_scores (
  uid         UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id     UUID REFERENCES users(uid) ON DELETE CASCADE,
  created_at  TIMESTAMPTZ DEFAULT now(),
  score       INT4,
  feedback    JSONB
);
The feedback column is stored as JSONB, which allows efficient querying and indexing of individual feedback points if needed in the future.

AI Prompt Structure

The Groq API is called via client.responses.create with model "openai/gpt-oss-20b". The prompt enforces strict JSON-only output with no markdown or prose:
Must Not Use Any Ai Words
Analyze this resume and return ONLY a valid JSON object with no markdown,
no backticks, no explanation.
Strictly follow this format:
{
  "ats_scores": <number between 0-100>,
  "feedback": [
    "<feedback point 1>",
    "<feedback point 2>",
    "<feedback point 3>"
  ]
}
Resume: <extracted text>
The response from the model is parsed directly with JSON.parse() via result.output_text. The ats_scores value from the model response is stored as score in the ats_scores database table. If the model deviates from the expected format, the parse will throw and the upload transaction is rolled back.

Environment Variable

The GROK_API environment variable must be set to a valid Groq API key. Without it, the OpenAI client initialization in grok.js will fail and all resume uploads will return a 500 error at the AI analysis step.
# .env (backend)
GROK_API=gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
For the best results, tailor your resume to each job you apply for. Upload a version that includes keywords from the specific job description — the ATS model rewards relevance between your resume text and common job-posting language. A score above 75 is generally considered strong for automated screening systems.

Build docs developers (and LLMs) love