openapi: 3.0.3
info:
  title: AI Dev Jobs API
  description: REST API for searching, posting, and applying to AI/ML developer jobs. Built for agentic access. No authentication required for read endpoints.
  version: "1.1"
  contact:
    email: hello@aidevboard.com
servers:
  - url: https://aidevboard.com/api/v1
paths:
  /jobs:
    get:
      summary: Search and list AI developer jobs
      operationId: listJobs
      parameters:
        - name: q
          in: query
          description: Full-text search (searches title, description, company name, and tags)
          schema:
            type: string
        - name: tags
          in: query
          description: Comma-separated tags to filter by (e.g., llm,pytorch,python)
          schema:
            type: string
        - name: location
          in: query
          description: Location filter (partial match)
          schema:
            type: string
        - name: workplace
          in: query
          description: Workplace type. Also accepts remote=true as shorthand for workplace=remote.
          schema:
            type: string
            enum: [remote, hybrid, onsite]
        - name: type
          in: query
          description: Job type (also accepts job_type as alias)
          schema:
            type: string
            enum: [full-time, part-time, contract, freelance]
        - name: level
          in: query
          description: Experience level
          schema:
            type: string
            enum: [junior, mid, senior, lead, principal]
        - name: salary_min
          in: query
          description: Minimum salary filter in USD/year (e.g., 200000)
          schema:
            type: integer
        - name: salary_max
          in: query
          description: Maximum salary filter in USD/year — matches jobs whose min salary is below this (range overlap)
          schema:
            type: integer
        - name: salary_floor_min
          in: query
          description: Strict floor filter — job's minimum salary must be >= this value. Use instead of salary_min when you need guaranteed minimums, not range overlap.
          schema:
            type: integer
        - name: posted_within_days
          in: query
          description: Only jobs posted within the last N days (1-90). Useful for polling clients that want fresh-only results. Clamped to 90 server-side.
          schema:
            type: integer
            minimum: 1
            maximum: 90
        - name: limit
          in: query
          description: Results per page (default 20, max 50)
          schema:
            type: integer
            default: 20
        - name: page
          in: query
          description: Page number (1-indexed, default 1)
          schema:
            type: integer
            default: 1
      responses:
        "200":
          description: Paginated list of jobs
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobs:
                    type: array
                    items:
                      $ref: "#/components/schemas/Job"
                  total:
                    type: integer
                    description: Total matching jobs across all pages
                  page:
                    type: integer
                  per_page:
                    type: integer
                  total_pages:
                    type: integer
                  has_next:
                    type: boolean
  /jobs/{id}:
    get:
      summary: Get a specific job by ID
      operationId: getJob
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Full job details including description, requirements, apply URL
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Job"
        "404":
          description: Job not found
  /jobs/{id}/similar:
    get:
      summary: Find similar jobs
      operationId: similarJobs
      description: Returns jobs similar to the given job, scored by tag overlap, workplace, experience level, and job type match.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          description: Max results (1-20, default 5)
          schema:
            type: integer
            default: 5
      responses:
        "200":
          description: Similar jobs ranked by similarity score
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string
                  similar:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        title:
                          type: string
                        company_name:
                          type: string
                        similarity_score:
                          type: integer
                        url:
                          type: string
                  total:
                    type: integer
        "404":
          description: Job not found
  /jobs/match:
    post:
      summary: Match jobs to a candidate profile — returns ranked results
      operationId: matchJobs
      description: Send a candidate profile (skills, salary range, workplace preference) and get jobs ranked by relevance score. No authentication required. This is the recommended endpoint for agentic job search.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [skills]
              properties:
                skills:
                  type: array
                  items:
                    type: string
                  description: Candidate skills (e.g., ["python", "llm", "pytorch"])
                salary_min:
                  type: integer
                  description: Desired minimum salary (USD/year)
                salary_max:
                  type: integer
                  description: Desired maximum salary (USD/year)
                workplace:
                  type: string
                  enum: [remote, hybrid, onsite]
                level:
                  type: string
                  enum: [junior, mid, senior, lead, principal]
                limit:
                  type: integer
                  description: Max results (default 20, max 50)
      responses:
        "200":
          description: Ranked job matches with scores and reasons
          content:
            application/json:
              schema:
                type: object
                properties:
                  matches:
                    type: array
                    items:
                      allOf:
                        - $ref: "#/components/schemas/Job"
                        - type: object
                          properties:
                            match_score:
                              type: integer
                            matched_tags:
                              type: array
                              items:
                                type: string
                            match_reasons:
                              type: array
                              items:
                                type: string
                  total_scored:
                    type: integer
                  total_matches:
                    type: integer
  /tags:
    get:
      summary: List popular tags with job counts
      operationId: listTags
      responses:
        "200":
          description: Map of tag names to job counts
  /stats:
    get:
      summary: AI developer job market statistics and salary benchmarks
      operationId: getStats
      description: Aggregate market data — salary distributions, top tags with avg salaries, company rankings, workplace breakdowns, experience levels. Updated from live data.
      responses:
        "200":
          description: Market statistics
  /companies:
    get:
      summary: List all companies with active job listings
      operationId: listCompanies
      responses:
        "200":
          description: Companies sorted by job count, with avg salary data
  /companies/{slug}:
    get:
      summary: Get company details, active jobs, and engagement stats
      operationId: getCompany
      parameters:
        - name: slug
          in: path
          required: true
          description: Company slug (e.g., anthropic, openai). Get slugs from /companies endpoint.
          schema:
            type: string
      responses:
        "200":
          description: Company info (name, slug, website, logo_url, avg_salary, salary_count, views, views_7d, clicks) plus all active job listings
        "404":
          description: Company not found
  /analytics/searches:
    get:
      summary: API search usage analytics
      operationId: searchAnalytics
      description: Aggregate search behavior — top queries, searched tags, user agents, zero-result searches. Useful for understanding what agents look for.
      parameters:
        - name: days
          in: query
          description: Lookback window in days (default 30, max 365)
          schema:
            type: integer
            default: 30
      responses:
        "200":
          description: Search analytics aggregates
  /pricing:
    get:
      summary: Available pricing tiers for company job listings
      operationId: listPricing
      description: Returns the set of paid tiers companies can choose from when posting jobs. Public endpoint — no auth required.
      responses:
        "200":
          description: Pricing tier list
          content:
            application/json:
              schema:
                type: object
                properties:
                  tiers:
                    type: array
                    items:
                      type: object
                      properties:
                        id:          { type: string }
                        name:        { type: string }
                        price_cents: { type: integer }
                        features:    { type: array, items: { type: string } }
  /subscribe:
    post:
      summary: Subscribe to the weekly AI Dev Jobs newsletter
      operationId: subscribe
      description: Email digest of new AI/ML roles. Default frequency is weekly. Tags optional to narrow the digest.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:     { type: string, format: email }
                name:      { type: string }
                tags:      { type: array, items: { type: string }, description: "Filter digest to these tags (e.g. python, remote)" }
                frequency: { type: string, enum: [daily, weekly, monthly], default: weekly }
      responses:
        "200":
          description: Subscribed (or already subscribed — idempotent)
        "400":
          description: Invalid email
  /salary-trends:
    get:
      summary: Historical salary trend snapshots
      operationId: salaryTrends
      description: Daily snapshot time-series of average and median AI/ML salaries across the index. Useful for agents comparing compensation over time or powering salary-trend charts.
      parameters:
        - name: days
          in: query
          description: Lookback window in days (default 90, max 365)
          schema:
            type: integer
            default: 90
      responses:
        "200":
          description: Time-series of salary snapshots
          content:
            application/json:
              schema:
                type: object
                properties:
                  snapshots:
                    type: array
                    items:
                      type: object
                      properties:
                        date:          { type: string, format: date }
                        avg_salary:    { type: number }
                        median_salary: { type: number }
                        job_count:     { type: integer }
  /trending/companies:
    get:
      summary: Companies hiring most aggressively in the last N days
      operationId: trendingCompanies
      description: |
        Returns companies ranked by count of new AI/ML jobs posted in
        the trailing N days. REST peer of the MCP get_trending_companies
        tool — same query, same ordering. Pairs with /stats (which has
        trending_tags_7d) to answer "what's the AI hiring market doing
        this week?"
      parameters:
        - name: days
          in: query
          description: Look-back window in days (default 7, max 30)
          schema:
            type: integer
            minimum: 1
            maximum: 30
            default: 7
        - name: limit
          in: query
          description: Max results (default 10, max 25)
          schema:
            type: integer
            minimum: 1
            maximum: 25
            default: 10
      responses:
        "200":
          description: Company leaderboard
          content:
            application/json:
              schema:
                type: object
                properties:
                  days:
                    type: integer
                  companies:
                    type: array
                    items:
                      type: object
                      properties:
                        name:     { type: string }
                        slug:     { type: string }
                        logo_url: { type: string }
                        new_jobs: { type: integer }
  /register/developer:
    post:
      summary: Register for a developer API key (free)
      operationId: registerDeveloper
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email]
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
      responses:
        "201":
          description: API key returned
  /register/company:
    post:
      summary: Register a company for posting jobs
      operationId: registerCompany
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email]
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                website:
                  type: string
      responses:
        "201":
          description: Company created with API key
  /developer/apply/{job_id}:
    post:
      summary: Apply to a job (requires developer API key)
      operationId: applyToJob
      security:
        - apiKey: []
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                cover_letter:
                  type: string
                skills:
                  type: array
                  items:
                    type: string
                experience_years:
                  type: integer
                github_url:
                  type: string
      responses:
        "201":
          description: Application submitted
  /developer/subscribe:
    post:
      summary: Upgrade API key to Pro tier ($49/mo)
      operationId: subscribePro
      description: Creates a Stripe subscription checkout session. Returns checkout_url to complete payment. After payment, your API key is upgraded to 5,000 req/hr.
      security:
        - apiKey: []
      responses:
        "200":
          description: Checkout URL returned (or auto-upgraded in test mode)
        "400":
          description: Already on Pro tier
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
  schemas:
    Job:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        company_name:
          type: string
        description:
          type: string
        requirements:
          type: string
        location:
          type: string
        workplace:
          type: string
          enum: [remote, hybrid, onsite]
        job_type:
          type: string
        experience_level:
          type: string
        salary_min:
          type: integer
          nullable: true
        salary_max:
          type: integer
          nullable: true
        tags:
          type: array
          items:
            type: string
        apply_url:
          type: string
        slug:
          type: string
        quality_score:
          type: integer
          description: "Listing quality 0-100 based on salary data, description detail, tags, location specificity"
        created_at:
          type: string
          format: date-time
