{
  "openapi": "3.1.0",
  "info": {
    "title": "Hilyt API",
    "version": "1.2.0",
    "description": "Edit your Hilyt profile (open, AI-readable profiles for people and businesses) programmatically or from an AI assistant. Auth: Authorization: Bearer hl_live_… — mint tokens in the Hilyt dashboard (Connect your AI). 60 requests/min per token. Facts belong in claims: dated where known, each with a source URL, confirmed by the profile owner. Publishing is always the explicit discoverable endpoint; a profile's first publish runs a one-time moderation screen and may return 422 with a reason."
  },
  "servers": [
    { "url": "https://dtnqoystawhvxegrvusu.supabase.co/functions/v1/api-v1" }
  ],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/v1/profiles": {
      "get": {
        "operationId": "listMyProfiles",
        "summary": "List profiles owned by this token's account",
        "responses": { "200": { "description": "Owned profiles (username, display_name, entity_type, discoverable, one_liner)." } }
      },
      "post": {
        "operationId": "createProfile",
        "summary": "Create a new PRIVATE profile (publish separately)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["username", "display_name", "entity_type"],
                "properties": {
                  "username": { "type": "string", "pattern": "^[a-z0-9_-]{3,30}$", "description": "Permanent URL slug (i.hilyt.it/<username>)." },
                  "display_name": { "type": "string", "maxLength": 60 },
                  "entity_type": { "type": "string", "enum": ["person", "organization"] },
                  "one_liner": { "type": "string", "maxLength": 120 },
                  "description": { "type": "string", "maxLength": 300 },
                  "role": { "type": "string", "maxLength": 60 },
                  "company": { "type": "string", "maxLength": 60 },
                  "location": { "type": "string", "maxLength": 60 },
                  "skills": { "type": "array", "items": { "type": "string", "maxLength": 30 }, "maxItems": 15 },
                  "primary_url": { "type": "string", "description": "Organization profiles only: the org's own canonical website URL." }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Created private. 3 new profiles per account per day." },
          "409": { "description": "Username taken." },
          "429": { "description": "Creation limit reached." }
        }
      }
    },
    "/v1/profiles/{username}": {
      "get": {
        "operationId": "getProfile",
        "summary": "Full editable state: profile, links, claims, FAQs, pending testimonials, URLs",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Full state." }, "404": { "description": "Not owned by this account." } }
      },
      "patch": {
        "operationId": "updateProfile",
        "summary": "Update whitelisted profile fields",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Any of: display_name, one_liner, description, role, company, location, skills, availability_status (open|busy|not_looking), availability_note, brand_color (hex), photo_url, primary_url (org only). Never: username, tier, discoverable.",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": { "200": { "description": "Updated profile + list of changed fields." } }
      }
    },
    "/v1/profiles/{username}/links": {
      "put": {
        "operationId": "replaceLinks",
        "summary": "Replace the ENTIRE link list (links not included are removed)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["links"],
                "properties": {
                  "links": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["label", "url"],
                      "properties": { "label": { "type": "string", "maxLength": 30 }, "url": { "type": "string" } }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Saved links. Cap: 7 (free) / 50 (pro)." } }
      }
    },
    "/v1/profiles/{username}/claims": {
      "post": {
        "operationId": "addClaim",
        "summary": "Add a dated, sourced fact (saved unverified)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["claim_type", "text"],
                "properties": {
                  "claim_type": { "type": "string", "enum": ["role", "work", "education", "achievement", "fact"] },
                  "text": { "type": "string", "minLength": 5 },
                  "org": { "type": "string" },
                  "from_date": { "type": "string", "format": "date" },
                  "to_date": { "type": "string", "format": "date" },
                  "source_url": { "type": "string", "description": "Public http(s) URL evidencing the claim — strongly preferred." }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Created claim." } }
      }
    },
    "/v1/claims/{id}": {
      "patch": {
        "operationId": "updateClaim",
        "summary": "Edit a claim (content edits reset verification; verified alone toggles it)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "description": "Updated claim." } }
      },
      "delete": {
        "operationId": "deleteClaim",
        "summary": "Delete a claim (no undo)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Deleted." } }
      }
    },
    "/v1/profiles/{username}/faqs": {
      "post": {
        "operationId": "addFaq",
        "summary": "Add one FAQ Q&A (max 12 per profile)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["question", "answer"],
                "properties": {
                  "question": { "type": "string", "minLength": 5, "maxLength": 200 },
                  "answer": { "type": "string", "minLength": 5, "maxLength": 1000 }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Created FAQ item." } }
      }
    },
    "/v1/faqs/{id}": {
      "patch": {
        "operationId": "updateFaq",
        "summary": "Edit one FAQ item (question/answer/sort_order)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } },
        "responses": { "200": { "description": "Updated FAQ item." } }
      },
      "delete": {
        "operationId": "deleteFaq",
        "summary": "Delete one FAQ item (no undo)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Deleted." } }
      }
    },
    "/v1/testimonials/{id}/approve": {
      "post": {
        "operationId": "approveTestimonial",
        "summary": "Approve a pending testimonial (becomes public on all surfaces)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Approved." } }
      }
    },
    "/v1/testimonials/{id}": {
      "delete": {
        "operationId": "deleteTestimonial",
        "summary": "Delete a testimonial (pending or approved; no undo)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Deleted." } }
      }
    },
    "/v1/profiles/{username}/discoverable": {
      "post": {
        "operationId": "setDiscoverable",
        "summary": "THE publish switch (first publish runs a one-time moderation screen)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "required": ["discoverable"], "properties": { "discoverable": { "type": "boolean" } } }
            }
          }
        },
        "responses": {
          "200": { "description": "Publish state changed." },
          "422": { "description": "Declined by the moderation screen, with a reason. Appeals via the hilyt.it contact form." }
        }
      }
    },
    "/v1/profiles/{username}/preview": {
      "get": {
        "operationId": "previewAiView",
        "summary": "Render the llm.txt card exactly as AI crawlers receive it (includes unpublished drafts)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "llm_txt text + published flag + live URL." } }
      }
    },
    "/v1/profiles/{username}/ai-reads": {
      "get": {
        "operationId": "getAiReads",
        "summary": "Which AI crawlers actually fetched this profile",
        "parameters": [
          { "name": "username", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "days", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 30 } }
        ],
        "responses": { "200": { "description": "Totals by bot and surface + 20 most recent fetches." } }
      }
    },
    "/v1/profiles/{username}/faq/regenerate": {
      "post": {
        "operationId": "regenerateFaq",
        "summary": "Regenerate the ENTIRE FAQ from saved fields (replaces manual edits; 5/hour)",
        "parameters": [{ "name": "username", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "New FAQ set." } }
      }
    },
    "/v1/visibility-check": {
      "post": {
        "operationId": "checkAiVisibility",
        "summary": "Free AI-visibility scan of any public website (3/day per token)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": { "type": "string" },
                  "name": { "type": "string", "maxLength": 120 },
                  "query": { "type": "string", "maxLength": 200 }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "0-100 score with per-check verdicts and fixes." } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "hl_live_… token from the Hilyt dashboard (Connect your AI)." }
    }
  }
}
