openapi: 3.1.0
info:
  title: UFoundMe! Public Knowledge API
  version: 1.3.0
  description: >-
    Public, read-only UFoundMe! API for reviewed service facts and the multilingual FAQ
    in French, Dutch, English, German, Italian, Spanish and European Portuguese.
    It advertises the companion MCP server at https://ufoundme.eu/mcp.php. It does
    not expose accounts, orders, payments, chats, authentication secrets, private pet
    records or data from other services. The historical card route only returns fields already
    present on an active public card.
  contact:
    name: UFoundMe!
    url: https://ufoundme.eu/contact.php
servers:
  - url: https://ufoundme.eu/api/v1
security: []
tags:
  - name: Knowledge
    description: Cacheable public knowledge for people and AI agents.
  - name: Discovery
    description: API and MCP capability discovery.
  - name: Compatibility
    description: Historical active public-card reader.
paths:
  /status:
    get:
      tags: [Discovery]
      operationId: getUFoundMeStatus
      summary: Read service status and discover the MCP endpoint
      parameters:
        - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Public service status
          content:
            application/json:
              schema: {$ref: '#/components/schemas/StatusResponse'}
  /about:
    get:
      tags: [Knowledge]
      operationId: explainUFoundMe
      summary: Explain what UFoundMe! is and how it works
      parameters:
        - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Reviewed public service and product facts
          content:
            application/json:
              schema: {$ref: '#/components/schemas/KnowledgeResponse'}
        '422': {$ref: '#/components/responses/InvalidLanguage'}
  /faq:
    get:
      tags: [Knowledge]
      operationId: searchUFoundMeFaq
      summary: List or search the reviewed FAQ
      parameters:
        - $ref: '#/components/parameters/Language'
        - name: q
          in: query
          description: Optional search text. Omit it to list the FAQ.
          schema: {type: string, minLength: 1, maxLength: 160}
        - name: limit
          in: query
          description: Maximum 20 when q is supplied; maximum 50 when the complete FAQ is listed.
          schema: {type: integer, minimum: 1, maximum: 50, default: 50}
      responses:
        '200':
          description: Matching FAQ entries
          content:
            application/json:
              schema: {$ref: '#/components/schemas/FaqListResponse'}
        '422': {$ref: '#/components/responses/InvalidInput'}
  /where-to-buy:
    get:
      tags: [Knowledge]
      operationId: getUFoundMeWhereToBuy
      summary: Read current prices, preorder availability and delivery options
      parameters:
        - $ref: '#/components/parameters/Language'
        - name: country
          in: query
          description: Optional delivery country used to filter tracked and untracked options.
          schema: {type: string, enum: [BE, LU, FR, NL, DE]}
      responses:
        '200': {description: Reviewed commerce facts and official purchase links}
        '422': {$ref: '#/components/responses/InvalidInput'}
  /faq/{id}:
    get:
      tags: [Knowledge]
      operationId: getUFoundMeFaqAnswer
      summary: Read one translated FAQ answer by stable identifier
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string, pattern: '^faq-[0-9]{3}$', example: faq-002}
        - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: One reviewed FAQ answer
          content:
            application/json:
              schema: {$ref: '#/components/schemas/FaqAnswerResponse'}
        '404': {description: FAQ answer not found}
        '422': {$ref: '#/components/responses/InvalidLanguage'}
  /ai:
    get:
      tags: [Discovery]
      operationId: discoverUFoundMeAiInterfaces
      summary: Tell AI agents that the MCP exists and what it answers
      parameters:
        - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: MCP endpoint, protocols, tools, resources, prompts and exclusions
          content:
            application/json:
              schema: {$ref: '#/components/schemas/AiDiscoveryResponse'}
        '422': {$ref: '#/components/responses/InvalidLanguage'}
  /card/{slug}:
    get:
      tags: [Compatibility]
      operationId: getPublicPetCard
      summary: Read non-sensitive fields from an active public card
      parameters:
        - name: slug
          in: path
          required: true
          schema: {type: string, pattern: '^[a-f0-9]{32}$'}
      responses:
        '200': {description: Active public card without private owner data}
        '404': {description: Card absent or service inactive}
        '422': {description: Invalid public slug}
components:
  parameters:
    Language:
      name: lang
      in: query
      description: Published UFoundMe! knowledge locale; pt means European Portuguese (pt-PT).
      schema: {type: string, enum: [fr, nl, en, de, it, es, pt], default: fr}
  responses:
    InvalidLanguage:
      description: Unsupported language
    InvalidInput:
      description: Invalid search, language or limit
  schemas:
    StatusResponse:
      type: object
      required: [ok, service, version, status, knowledge_api, mcp]
      properties:
        ok: {type: boolean, const: true}
        service: {type: string, const: UFoundMe!}
        version: {type: string}
        status: {type: string}
        privacy: {type: string}
        knowledge_api: {type: string, format: uri}
        mcp: {type: string, format: uri, const: 'https://ufoundme.eu/mcp.php'}
    KnowledgeResponse:
      type: object
      required: [ok, data]
      properties:
        ok: {type: boolean, const: true}
        data: {type: object, additionalProperties: true}
    FaqItem:
      type: object
      required: [id, language, question, answer, canonical_url]
      properties:
        id: {type: string, pattern: '^faq-[0-9]{3}$'}
        language: {type: string, enum: [fr, nl, en, de, it, es, pt]}
        question: {type: string}
        answer: {type: string}
        canonical_url: {type: string, format: uri}
        score: {type: integer, minimum: 1}
    FaqListResponse:
      type: object
      required: [ok, language, query, count, items]
      properties:
        ok: {type: boolean, const: true}
        language: {type: string, enum: [fr, nl, en, de, it, es, pt]}
        query: {type: string}
        count: {type: integer, minimum: 0}
        items:
          type: array
          items: {$ref: '#/components/schemas/FaqItem'}
    FaqAnswerResponse:
      type: object
      required: [ok, data]
      properties:
        ok: {type: boolean, const: true}
        data: {$ref: '#/components/schemas/FaqItem'}
    AiDiscoveryResponse:
      type: object
      required: [ok, data]
      properties:
        ok: {type: boolean, const: true}
        data:
          type: object
          required: [message_for_ai_agents, mcp, api]
          additionalProperties: true
