openapi: 3.0.3
info:
  title: curaft API
  version: 1.0.0
  description: Semantic content discovery API for curaft feeds, embeds, and research workflows. Public access is available with IP-based rate limits.
  license:
    name: Commercial
    url: https://curaft.com/pricing
servers:
  - url: https://curaft.com
tags:
  - name: API
    description: API metadata and documentation.
  - name: Items
    description: Semantic content search.
  - name: Feeds
    description: Feed suggestion helpers.
paths:
  /api/v1:
    get:
      tags:
        - API
      operationId: getApiIndex
      summary: API index
      description: Returns API metadata, available endpoints, rate limits, and documentation links.
      security:
        - {}
      responses:
        "200":
          description: API index response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiIndexResponse"
        "429":
          description: Rate limit reached.
          headers:
            Retry-After:
              description: Seconds until the caller should retry.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/items:
    get:
      tags:
        - Items
      operationId: listItems
      summary: List curated items
      description: Returns normalized content items for one or more semantic queries. Usage is rate-limited by IP.
      security:
        - {}
      parameters:
        - name: query
          in: query
          description: One or more semantic search queries. Repeat query to combine several saved searches.
          required: false
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
          example:
            - AI search visibility
            - B2B SaaS marketing strategy
        - name: page
          in: query
          description: Page number.
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          description: Number of items to return. per_page is also accepted for compatibility.
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 20
        - name: sort
          in: query
          description: Result ordering.
          required: false
          schema:
            type: string
            enum:
              - relevance
              - newest
              - oldest
            default: relevance
        - name: time_range
          in: query
          description: Freshness window, for example last_7_days or last_30_days.
          required: false
          schema:
            type: string
            example: last_30_days
      responses:
        "200":
          description: Curated items response.
          headers:
            X-RateLimit-Limit:
              description: Request quota for the active rate-limit window.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the active window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Unix timestamp when the active window resets.
              schema:
                type: integer
            X-Curaft-API-Tier:
              description: The rate-limit tier used for this request.
              schema:
                type: string
                enum:
                  - free
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ItemsResponse"
              example:
                data:
                  - id: 25083462
                    title: Ontario to Extend Alcohol Sale and Serve Hours
                    url: https://example.com/story
                    summary: A concise normalized summary.
                    image: https://example.com/image.jpg
                    source:
                      id: 123
                      name: Foodservice & Hospitality
                      favicon: https://www.google.com/s2/favicons?domain=example.com
                      url: /sources/123-foodservice-hospitality
                    published_at: "2026-02-12T09:00:00Z"
                    score: 0.91
                    story_url: /stories/25083462-ontario-extend-alcohol-sale-serve-hours
                meta:
                  page: 1
                  limit: 10
                  next_page: 2
                  total: 148
                  source_count: 32
                links:
                  self: https://curaft.com/api/v1/items?query=AI%20search&sort=relevance&limit=10
                  next: https://curaft.com/api/v1/items?query=AI%20search&sort=relevance&limit=10&page=2
        "429":
          description: Rate limit reached.
          headers:
            Retry-After:
              description: Seconds until the caller should retry.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/feed-suggestions:
    get:
      tags:
        - Feeds
      operationId: listFeedSuggestions
      summary: List feed suggestions
      description: Returns preset and AI-assisted semantic feed suggestions for a natural-language query.
      security:
        - {}
      parameters:
        - name: q
          in: query
          description: Natural-language feed query. Empty returns preset feeds.
          required: false
          schema:
            type: string
          example: AI search visibility
      responses:
        "200":
          description: Feed suggestions response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeedSuggestionsResponse"
              example:
                data:
                  - name: AI
                    search: AI products, model releases, AI search, automation, applied machine learning, enterprise AI adoption
                    category: Technology
        "429":
          description: Rate limit reached.
          headers:
            Retry-After:
              description: Seconds until the caller should retry.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  schemas:
    ApiEndpoint:
      type: object
      properties:
        method:
          type: string
        path:
          type: string
        url:
          type: string
        description:
          type: string
        query:
          type: object
          additionalProperties:
            type: string
        example:
          type: string
          nullable: true
    ApiIndexResponse:
      type: object
      properties:
        name:
          type: string
        version:
          type: string
        description:
          type: string
        authentication:
          type: string
        docs_url:
          type: string
        openapi_url:
          type: string
        rate_limits:
          $ref: "#/components/schemas/ApiRateLimits"
        endpoints:
          type: array
          items:
            $ref: "#/components/schemas/ApiEndpoint"
    ApiRateLimits:
      type: object
      properties:
        free:
          type: object
          additionalProperties: true
    ErrorResponse:
      type: object
      properties:
        statusCode:
          type: integer
        statusMessage:
          type: string
        data:
          type: object
          nullable: true
          additionalProperties: true
    ItemSource:
      type: object
      properties:
        id:
          type: integer
          nullable: true
        name:
          type: string
        favicon:
          type: string
          nullable: true
        url:
          type: string
          nullable: true
    Item:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        url:
          type: string
        summary:
          type: string
        image:
          type: string
          nullable: true
        source:
          $ref: "#/components/schemas/ItemSource"
        published_at:
          type: string
          format: date-time
          nullable: true
        score:
          type: number
          nullable: true
        story_url:
          type: string
          nullable: true
    ItemsMeta:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        next_page:
          type: integer
          nullable: true
        total:
          type: integer
        source_count:
          type: integer
    PaginationLinks:
      type: object
      properties:
        self:
          type: string
        next:
          type: string
          nullable: true
    ItemsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Item"
        meta:
          $ref: "#/components/schemas/ItemsMeta"
        links:
          $ref: "#/components/schemas/PaginationLinks"
    FeedSuggestion:
      type: object
      properties:
        name:
          type: string
        search:
          type: string
        category:
          type: string
    FeedSuggestionsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/FeedSuggestion"
