Skip to main content
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

status
string
Comma-separated job statuses to filter by.Values: saved, applied, interview, offer, rejectedExample: status=applied,interview
source
string
Filter by job source.Values: brightermonday, fuzu, linkedin, manual
since
string
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
is_remote
boolean
Filter remote jobs.Values: true or false
min_score
number
Minimum AI match score (0-100).Example: min_score=75
limit
number
default:"100"
Maximum results per page.Range: 1-500
page
number
default:"1"
Page number (1-indexed).
sort
string
default:"created_at"
Field to sort by.Values: created_at, updated_at, ai_match_score, company_name
order
string
default:"desc"
Sort order.Values: asc, desc

Response

data
array
required
Array of job objects.
total
number
required
Total count across all pages.
page
number
required
Current page number.
limit
number
required
Items per page.
has_more
boolean
required
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
string
required
Company name.Max length: 255 characters
job_title
string
required
Job title/position.Max length: 255 characters
job_description
string
Full job description.
job_url
string
Link to job posting.Must be HTTPS (enforced by database constraint)
source
string
required
Job source.Values: brightermonday, fuzu, linkedin, manual
status
string
default:"saved"
Initial status.Values: saved, applied, interview, offer, rejected
location
string
Job location.
is_remote
boolean
Whether job is remote.
salary_range_min
number
Minimum salary (integer, e.g., 180000).
salary_range_max
number
Maximum salary (integer, e.g., 250000).
tags
array
User-defined tags.Example: ["high-priority", "backend"]

Response

data
object
required
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
object

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

id
string
required
Job UUID.

Response

data
object
required
Job object (same schema as List Jobs).
events
array
required
Last 20 events for this job, ordered by created_at descending.

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

id
string
required
Job UUID.

Request Body

All fields optional. Same schema as Create Job, plus:
status
string
Update application status.Values: saved, applied, interview, offer, rejected
notes
string
User notes.
interview_at
string
ISO 8601 timestamp of interview.
applied_at
string
ISO 8601 timestamp of application.
offer_at
string
ISO 8601 timestamp of offer.
rejected_at
string
ISO 8601 timestamp of rejection.

Response

data
object
required
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

id
string
required
Job UUID.

Response

success
boolean
required
Always true on success.

Example Response

{
  "success": true
}

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.

Build docs developers (and LLMs) love