openapi: "3.0.3"
info:
  title: "OfficialObituary API"
  version: "1.0.0"
  description: "Public obituary publishing and discovery API for OfficialObituary.com. The publish endpoint is public and rate-limited to 3 requests per hour per IP address."
servers:
  -
    url: "https://api.officialobituary.com"
    description: "Production"
  -
    url: "http://localhost:3000"
    description: "Local development"
tags:
  -
    name: "Obituaries"
    description: "Publish and retrieve obituaries"
  -
    name: "Search"
    description: "Search across published obituaries"
  -
    name: "Stats"
    description: "Directory and aggregation endpoints"
paths:
  "/api/obituaries/publish":
    post:
      tags:
        - "Obituaries"
      operationId: "publishObituary"
      summary: "Publish an obituary (public, no auth)"
      description: "Creates and publishes a public obituary page. Rate limit: 3 publish requests per hour per IP address."
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/PublishObituaryRequest"
            examples:
              agentPayload:
                summary: "Preferred agent payload"
                value:
                  full_name: "Margaret Anne Walker"
                  birth_date: "1941-08-12"
                  death_date: "2026-02-14"
                  life_story: "Margaret Anne Walker was a devoted teacher, mother, and choir director who spent 35 years serving families in Austin, Texas."
                  death_city: "Austin"
                  death_state: "TX"
                  service_date: "2026-02-20"
                  service_location: "St. Matthew Church, Austin, TX"
                  photo_url: "https://cdn.officialobituary.com/photos/margaret-walker.jpg"
                  survivors:
                    - "James Walker (spouse)"
                    - "Lily Walker (daughter)"
                  tone: "warm"
              legacyPayload:
                summary: "Legacy compatibility payload"
                value:
                  full_name: "John D. Miller"
                  birth_date: "1947-04-02"
                  death_date: "2026-02-10"
                  life_story: "John D. Miller passed away peacefully surrounded by family after a life of service and kindness."
                  obituary_text: "John D. Miller passed away peacefully surrounded by family after a life of service and kindness."
                  death_place: "Phoenix, AZ"
      responses:
        "201":
          description: "Obituary published successfully"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/PublishObituaryResponse"
              example:
                slug: "margaret-anne-walker-1941-2026"
                url: "https://officialobituary.com/obituaries/margaret-anne-walker-1941-2026"
                obituary_id: "sN3q5Jt8k1"
        "400":
          description: "Validation error"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
        "429":
          description: "Rate limit exceeded. Maximum 3 publish requests per hour per IP address."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
              example:
                error: "Too many publications. Please try again later."
                code: "RATE_LIMITED"
  "/api/obituaries":
    get:
      tags:
        - "Obituaries"
      operationId: "listObituaries"
      summary: "List published obituaries"
      parameters:
        -
          name: "q"
          in: "query"
          required: false
          schema:
            type: "string"
          description: "Optional search term"
        -
          name: "city"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "state"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "last_name"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "limit"
          in: "query"
          required: false
          schema:
            type: "integer"
            minimum: 1
            maximum: 100
            default: 20
        -
          name: "offset"
          in: "query"
          required: false
          schema:
            type: "integer"
            minimum: 0
            default: 0
        -
          name: "sort"
          in: "query"
          required: false
          schema:
            type: "string"
            enum:
              - "death_date"
              - "created_at"
            default: "death_date"
        -
          name: "order"
          in: "query"
          required: false
          schema:
            type: "string"
            enum:
              - "asc"
              - "desc"
            default: "desc"
      responses:
        "200":
          description: "Paginated obituary list"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ObituaryListResponse"
              example:
                data:
                  -
                    id: "sN3q5Jt8k1"
                    slug: "margaret-anne-walker-1941-2026"
                    full_name: "Margaret Anne Walker"
                    birth_date: "1941-08-12"
                    death_date: "2026-02-14"
                    death_city: "Austin"
                    death_state: "TX"
                    status: "published"
                meta:
                  total: 1
                  limit: 20
                  offset: 0
                  has_more: false
  "/api/obituaries/{id}":
    get:
      tags:
        - "Obituaries"
      operationId: "getObituaryById"
      summary: "Get one obituary by ID"
      parameters:
        -
          name: "id"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        "200":
          description: "Obituary record"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/Obituary"
        "404":
          description: "Obituary not found"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
        "410":
          description: "Obituary removed"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/search":
    get:
      tags:
        - "Search"
      operationId: "searchObituaries"
      summary: "Search published obituaries"
      parameters:
        -
          name: "q"
          in: "query"
          required: true
          schema:
            type: "string"
            minLength: 1
          description: "Full text query"
        -
          name: "city"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "state"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "funeral_home"
          in: "query"
          required: false
          schema:
            type: "string"
        -
          name: "date_from"
          in: "query"
          required: false
          schema:
            type: "string"
            format: "date"
        -
          name: "date_to"
          in: "query"
          required: false
          schema:
            type: "string"
            format: "date"
        -
          name: "limit"
          in: "query"
          required: false
          schema:
            type: "integer"
            minimum: 1
            maximum: 100
            default: 20
        -
          name: "offset"
          in: "query"
          required: false
          schema:
            type: "integer"
            minimum: 0
            default: 0
      responses:
        "200":
          description: "Search results"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/SearchResponse"
              example:
                results:
                  -
                    id: "sN3q5Jt8k1"
                    slug: "margaret-anne-walker-1941-2026"
                    fullName: "Margaret Anne Walker"
                    birthDate: "1941-08-12"
                    deathDate: "2026-02-14"
                    city: "Austin"
                    state: "TX"
                    photoUrl: "https://cdn.officialobituary.com/photos/margaret-walker.jpg"
                    snippet: "Margaret Anne Walker was a devoted teacher..."
                total: 1
                query: "walker"
                took: 12
                meta:
                  limit: 20
                  offset: 0
                  hasMore: false
  "/api/obituaries/stats/states":
    get:
      tags:
        - "Stats"
      operationId: "getObituaryStateStats"
      summary: "Get obituary counts by state"
      responses:
        "200":
          description: "State directory stats"
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/StateStatsResponse"
              example:
                total: 245
                states:
                  -
                    state: "TX"
                    count: 28
                    cities:
                      - "Austin"
                      - "Dallas"
                      - "Houston"
                  -
                    state: "CA"
                    count: 24
                    cities:
                      - "Los Angeles"
                      - "San Diego"
                      - "San Jose"
components:
  schemas:
    PublishTone:
      type: "string"
      enum:
        - "professional"
        - "warm"
        - "religious"
    PublishObituaryRequest:
      type: "object"
      required:
        - "full_name"
        - "birth_date"
        - "death_date"
        - "life_story"
      properties:
        full_name:
          type: "string"
          example: "Margaret Anne Walker"
        birth_date:
          type: "string"
          format: "date"
          pattern: "^\\d{4}-\\d{2}-\\d{2}$"
          example: "1941-08-12"
        death_date:
          type: "string"
          format: "date"
          pattern: "^\\d{4}-\\d{2}-\\d{2}$"
          example: "2026-02-14"
        life_story:
          type: "string"
          example: "Margaret Anne Walker was a devoted teacher, mother, and choir director who spent 35 years serving families in Austin, Texas."
        death_city:
          type: "string"
          example: "Austin"
        death_state:
          type: "string"
          example: "TX"
        service_date:
          type: "string"
          format: "date"
          example: "2026-02-20"
        service_location:
          type: "string"
          example: "St. Matthew Church, Austin, TX"
        photo_url:
          type: "string"
          format: "uri"
          example: "https://cdn.officialobituary.com/photos/margaret-walker.jpg"
        survivors:
          type: "array"
          items:
            type: "string"
          example:
            - "James Walker (spouse)"
            - "Lily Walker (daughter)"
        tone:
          "$ref": "#/components/schemas/PublishTone"
        obituary_text:
          type: "string"
          deprecated: true
          description: "Legacy field accepted for backward compatibility. Use life_story."
        death_place:
          type: "string"
          deprecated: true
          description: "Legacy field accepted for backward compatibility. Use death_city/death_state."
    PublishObituaryResponse:
      type: "object"
      required:
        - "slug"
        - "url"
        - "obituary_id"
      properties:
        slug:
          type: "string"
          example: "margaret-anne-walker-1941-2026"
        url:
          type: "string"
          format: "uri"
          example: "https://officialobituary.com/obituaries/margaret-anne-walker-1941-2026"
        obituary_id:
          type: "string"
          example: "sN3q5Jt8k1"
        success:
          type: "boolean"
          example: true
        id:
          type: "string"
          description: "Legacy alias of obituary_id"
          example: "sN3q5Jt8k1"
    Obituary:
      type: "object"
      properties:
        id:
          type: "string"
        slug:
          type: "string"
        full_name:
          type: "string"
        birth_date:
          type: "string"
          format: "date"
        death_date:
          type: "string"
          format: "date"
        age:
          type: "integer"
          nullable: true
        death_place:
          type: "string"
          nullable: true
        death_city:
          type: "string"
          nullable: true
        death_state:
          type: "string"
          nullable: true
        obituary_text:
          type: "string"
        photo_url:
          type: "string"
          nullable: true
        service_date:
          type: "string"
          format: "date"
          nullable: true
        service_location:
          type: "string"
          nullable: true
        source_type:
          type: "string"
        status:
          type: "string"
        created_at:
          type: "string"
        updated_at:
          type: "string"
        published_at:
          type: "string"
          nullable: true
    ObituaryListResponse:
      type: "object"
      properties:
        data:
          type: "array"
          items:
            "$ref": "#/components/schemas/Obituary"
        meta:
          type: "object"
          properties:
            total:
              type: "integer"
            limit:
              type: "integer"
            offset:
              type: "integer"
            has_more:
              type: "boolean"
    SearchResult:
      type: "object"
      properties:
        id:
          type: "string"
        slug:
          type: "string"
        fullName:
          type: "string"
        birthDate:
          type: "string"
          format: "date"
        deathDate:
          type: "string"
          format: "date"
        age:
          type: "integer"
          nullable: true
        city:
          type: "string"
          nullable: true
        state:
          type: "string"
          nullable: true
        photoUrl:
          type: "string"
          nullable: true
        snippet:
          type: "string"
        funeralHome:
          type: "object"
          nullable: true
          properties:
            name:
              type: "string"
            city:
              type: "string"
    SearchResponse:
      type: "object"
      properties:
        results:
          type: "array"
          items:
            "$ref": "#/components/schemas/SearchResult"
        total:
          type: "integer"
        query:
          type: "string"
        took:
          type: "integer"
          description: "Execution time in ms"
        meta:
          type: "object"
          properties:
            limit:
              type: "integer"
            offset:
              type: "integer"
            hasMore:
              type: "boolean"
    StateStatsResponse:
      type: "object"
      properties:
        total:
          type: "integer"
        states:
          type: "array"
          items:
            type: "object"
            properties:
              state:
                type: "string"
              count:
                type: "integer"
              cities:
                type: "array"
                items:
                  type: "string"
    ErrorResponse:
      type: "object"
      properties:
        error:
          type: "string"
        code:
          type: "string"
          nullable: true