Manage job applications with full CRUD operations. All endpoints require authentication.
List Jobs
curl -X GET "https://api.pipeline.local/api/jobs?status=applied,interview&limit=20&page=1" \
-H "Authorization: Bearer YOUR_TOKEN"
Fetch paginated list of jobs with filtering, search, and sorting.
Authentication
Required. User can only access their own jobs (enforced by RLS).
Query Parameters
Comma-separated job statuses to filter by. Values: saved, applied, interview, offer, rejectedExample: status=applied,interview
Filter by job source. Values: brightermonday, fuzu, linkedin, manual
ISO 8601 timestamp. Only return jobs updated after this time. Example: 2026-03-01T00:00:00Z
Full-text search across company name and job title. Max length: 200 characters
Filter remote jobs. Values: true or false
Minimum AI match score (0-100). Example: min_score=75
Maximum results per page. Range: 1-500
sort
string
default: "created_at"
Field to sort by. Values: created_at, updated_at, ai_match_score, company_name
Sort order. Values: asc, desc
Response
Array of job objects. Link to job posting (HTTPS only).
Job source: brightermonday, fuzu, linkedin, or manual.
Application status: saved, applied, interview, offer, or rejected.
AI match score (0-100). null if not yet scored.
AI explanation for match score.
Structured data extracted by AI. Salary information. Currency code (e.g., USD).
Required experience: junior, mid, senior, lead, or staff.
ISO 8601 timestamp of application.
ISO 8601 timestamp of interview.
ISO 8601 timestamp of offer.
ISO 8601 timestamp of rejection.
Minimum salary (integer, e.g., 180000).
Maximum salary (integer, e.g., 250000).
ISO 8601 timestamp of creation.
ISO 8601 timestamp of last update.
ISO 8601 timestamp of last scrape.
ISO 8601 timestamp of last sync.
ISO 8601 timestamp of soft delete.
Total count across all pages.
Whether more pages exist.
Example Response
{
"data" : [
{
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"user_id" : "user_abc123" ,
"company_name" : "Acme Corp" ,
"job_title" : "Senior Backend Engineer" ,
"job_description" : "Build scalable APIs..." ,
"job_url" : "https://acme.com/careers/senior-backend-engineer" ,
"source" : "linkedin" ,
"status" : "applied" ,
"ai_match_score" : 87 ,
"ai_reasoning" : "Strong match: 5+ years Go experience, distributed systems expertise" ,
"ai_parsed_data" : {
"skills" : [ "Go" , "PostgreSQL" , "Docker" , "Kubernetes" ],
"experience_level" : "senior" ,
"remote" : true
},
"applied_at" : "2026-03-01T10:30:00Z" ,
"interview_at" : null ,
"offer_at" : null ,
"rejected_at" : null ,
"notes" : "Met recruiter at tech conference" ,
"tags" : [ "high-priority" , "backend" ],
"salary_range_min" : 180000 ,
"salary_range_max" : 250000 ,
"location" : "San Francisco, CA" ,
"is_remote" : true ,
"created_at" : "2026-02-28T15:00:00Z" ,
"updated_at" : "2026-03-01T10:30:00Z" ,
"scraped_at" : null ,
"last_synced_at" : null ,
"deleted_at" : null
}
],
"total" : 42 ,
"page" : 1 ,
"limit" : 20 ,
"has_more" : true
}
Status: ✅ Live
This endpoint is fully implemented. See app/api/jobs/route.ts:13.
Create Job
curl -X POST "https://api.pipeline.local/api/jobs" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"company_name": "Acme Corp",
"job_title": "Senior Backend Engineer",
"job_url": "https://acme.com/careers/123",
"source": "linkedin",
"status": "saved",
"location": "San Francisco, CA",
"is_remote": true,
"salary_range_min": 180000,
"salary_range_max": 250000
}'
Create a new job application.
Authentication
Required. Job is automatically associated with authenticated user.
Request Body
Company name. Max length: 255 characters
Job title/position. Max length: 255 characters
Link to job posting. Must be HTTPS (enforced by database constraint)
Job source. Values: brightermonday, fuzu, linkedin, manual
Initial status. Values: saved, applied, interview, offer, rejected
Minimum salary (integer, e.g., 180000).
Maximum salary (integer, e.g., 250000).
User-defined tags. Example: ["high-priority", "backend"]
Response
The created job object (same schema as List Jobs).
Example Response
{
"data" : {
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"user_id" : "user_abc123" ,
"company_name" : "Acme Corp" ,
"job_title" : "Senior Backend Engineer" ,
"job_url" : "https://acme.com/careers/123" ,
"source" : "linkedin" ,
"status" : "saved" ,
"location" : "San Francisco, CA" ,
"is_remote" : true ,
"salary_range_min" : 180000 ,
"salary_range_max" : 250000 ,
"created_at" : "2026-03-04T10:00:00Z" ,
"updated_at" : "2026-03-04T10:00:00Z" ,
"ai_match_score" : null ,
"ai_reasoning" : null ,
"notes" : null ,
"tags" : null ,
"deleted_at" : null
}
}
Errors
Error code: VALIDATION_ERROR, INVALID_JSON, UNAUTHORIZED, INTERNAL_ERROR
Human-readable error message.
Validation errors (if code is VALIDATION_ERROR). Each item contains path, message, and code from Zod validation.
Status: ✅ Live
This endpoint is fully implemented. See app/api/jobs/route.ts:129.
Note: A job_created event is automatically logged by database trigger (log_job_changes).
Get Job
curl -X GET "https://api.pipeline.local/api/jobs/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_TOKEN"
Fetch a single job by ID with recent events.
Authentication
Required. User can only access their own jobs.
Path Parameters
Response
Job object (same schema as List Jobs).
Last 20 events for this job, ordered by created_at descending. Event type: job_created, status_changed, ai_scored, note_added, application_sent, interview_scheduled, offer_received, rejected.
Event metadata (e.g., { "old_status": "saved", "new_status": "applied" }).
Example Response
{
"data" : {
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"company_name" : "Acme Corp" ,
"job_title" : "Senior Backend Engineer" ,
"status" : "interview" ,
"created_at" : "2026-02-28T15:00:00Z" ,
"updated_at" : "2026-03-02T09:00:00Z"
},
"events" : [
{
"id" : "evt_001" ,
"user_id" : "user_abc123" ,
"job_id" : "123e4567-e89b-12d3-a456-426614174000" ,
"event_type" : "status_changed" ,
"event_data" : {
"old_status" : "applied" ,
"new_status" : "interview"
},
"created_at" : "2026-03-02T09:00:00Z"
},
{
"id" : "evt_002" ,
"event_type" : "status_changed" ,
"event_data" : {
"old_status" : "saved" ,
"new_status" : "applied"
},
"created_at" : "2026-03-01T10:30:00Z"
}
]
}
Errors
404 Not Found — Job doesn’t exist or doesn’t belong to user
401 Unauthorized — Missing or invalid auth token
500 Internal Error — Database error
Status: ✅ Live
This endpoint is fully implemented. See app/api/jobs/[id]/route.ts:12.
Update Job
curl -X PATCH "https://api.pipeline.local/api/jobs/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "interview",
"interview_at": "2026-03-10T14:00:00Z",
"notes": "Phone screen scheduled for next week"
}'
Update an existing job. All fields are optional; only provided fields are updated.
Authentication
Required. User can only update their own jobs.
Path Parameters
Request Body
All fields optional. Same schema as Create Job, plus:
Update application status. Values: saved, applied, interview, offer, rejected
ISO 8601 timestamp of interview.
ISO 8601 timestamp of application.
ISO 8601 timestamp of offer.
ISO 8601 timestamp of rejection.
Response
Updated job object (same schema as List Jobs).
Example Response
{
"data" : {
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"company_name" : "Acme Corp" ,
"job_title" : "Senior Backend Engineer" ,
"status" : "interview" ,
"interview_at" : "2026-03-10T14:00:00Z" ,
"notes" : "Phone screen scheduled for next week" ,
"updated_at" : "2026-03-04T11:00:00Z"
}
}
Errors
404 Not Found — Job doesn’t exist or doesn’t belong to user
400 Validation Error — Invalid input
401 Unauthorized — Missing or invalid auth token
500 Internal Error — Database error
Status: ✅ Live
This endpoint is fully implemented. See app/api/jobs/[id]/route.ts:61.
Note: A status_changed event is automatically logged by database trigger if status changed.
Delete Job
curl -X DELETE "https://api.pipeline.local/api/jobs/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_TOKEN"
Soft-delete a job by setting deleted_at timestamp. Job remains in database but is excluded from queries.
Authentication
Required. User can only delete their own jobs.
Path Parameters
Response
Example Response
Errors
404 Not Found — Job doesn’t exist, doesn’t belong to user, or already deleted
401 Unauthorized — Missing or invalid auth token
500 Internal Error — Database error
Status: ✅ Live
This endpoint is fully implemented. See app/api/jobs/[id]/route.ts:150.
Note: Soft delete allows recovery via database if needed. To permanently delete, admins can run DELETE FROM jobs WHERE deleted_at IS NOT NULL.