openapi: 3.1.0
info:
  title: Refynes Public API
  version: "1.0.0"
  summary: Public endpoints for AI agents — blog content, aggregated job board, and product discovery.
  description: |
    Refynes is an AI resume builder, ATS scanner, job board, and auto-apply
    platform. This OpenAPI spec covers the **public, no-auth** endpoints that
    AI agents (Custom GPTs, Claude tools, Perplexity actions) can call
    directly.

    For authenticated user operations (list / tailor saved resumes, query the
    AI career coach), connect to the Refynes MCP server at
    `https://us-central1-cv-builder-8eec3.cloudfunctions.net/mcpServer`
    using a Refynes API key.
  contact:
    name: Refynes (Softcodedesign Inc.)
    url: https://refynes.ca
    email: info@softcodedesign.com
  license:
    name: Proprietary
servers:
  - url: https://refynes.ca/api
    description: Production
tags:
  - name: Blog
    description: Public blog content — resume tips, ATS strategies, career advice.
  - name: Jobs
    description: Aggregated job listings across 7 sources (Job Bank Canada, Adzuna, Jooble, Talent.com, The Muse, Remotive, JobRapido).
paths:
  /blog/list:
    get:
      tags: [Blog]
      operationId: listBlogPosts
      summary: List the 50 most-recent published Refynes blog posts.
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  posts:
                    type: array
                    items: { $ref: '#/components/schemas/BlogPostSummary' }
  /blog/post/{slug}:
    get:
      tags: [Blog]
      operationId: getBlogPost
      summary: Fetch a single blog post by slug, with 3 related posts.
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  post: { $ref: '#/components/schemas/BlogPost' }
                  related:
                    type: array
                    items: { $ref: '#/components/schemas/BlogPostSummary' }
        "404":
          description: Post not found
  /jobs/search:
    get:
      tags: [Jobs]
      operationId: searchJobs
      summary: Aggregated job search across 7 sources.
      description: |
        Aggregates live results from Job Bank Canada, Adzuna, Jooble,
        Talent.com, The Muse, Remotive, and JobRapido. Up to 200 results
        per query. Cached at the CDN edge for 5 minutes.
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          description: Keywords (e.g. "senior product designer")
        - name: location
          in: query
          required: false
          schema: { type: string, default: "Canada" }
        - name: country
          in: query
          required: false
          schema: { type: string, default: "Canada" }
        - name: city
          in: query
          required: false
          schema: { type: string }
        - name: postedWithin
          in: query
          required: false
          schema: { type: string, enum: [today, "3d", "7d", "30d", any], default: any }
        - name: remote
          in: query
          required: false
          schema: { type: string, enum: ["true", "false"] }
        - name: limit
          in: query
          required: false
          schema: { type: integer, default: 120, minimum: 1, maximum: 200 }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobs:
                    type: array
                    items: { $ref: '#/components/schemas/JobListing' }
                  meta:
                    type: object
                    properties:
                      count: { type: integer }
                      location: { type: string }
                      country: { type: string }
                      city: { type: string }
                      postedWithin: { type: string }
  /jobs/detail:
    get:
      tags: [Jobs]
      operationId: getJobDetail
      summary: Fetch full details for a specific job by id + source.
      parameters:
        - name: id
          in: query
          required: true
          schema: { type: string }
        - name: source
          in: query
          required: true
          schema:
            type: string
            enum: [jobbankca, adzuna, jooble, talent, themuse, remotive, jobrapido]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  job: { $ref: '#/components/schemas/JobListing' }

components:
  schemas:
    BlogPostSummary:
      type: object
      properties:
        slug:        { type: string }
        title:       { type: string }
        excerpt:     { type: string }
        publishedAt: { type: string, format: date-time }
        updatedAt:   { type: string, format: date-time }
        imageId:     { type: string }
        authorEmail: { type: string }
        url:         { type: string, format: uri }

    BlogPost:
      allOf:
        - $ref: '#/components/schemas/BlogPostSummary'
        - type: object
          properties:
            body:    { type: string, description: "Markdown body" }
            related: { type: array, items: { type: string }, description: "Related post slugs" }

    JobListing:
      type: object
      properties:
        id:           { type: string }
        source:       { type: string }
        title:        { type: string }
        company:      { type: string }
        location:     { type: string }
        url:          { type: string, format: uri }
        remote:       { type: boolean }
        salary:       { type: string }
        postedAt:     { type: string, format: date-time }
        description:  { type: string }
        modeFilters:
          type: object
          properties:
            remote: { type: boolean }
            onsite: { type: boolean }
            hybrid: { type: boolean }
