openapi: "3.1.0"
info:
  title: Tashvi AI Content API
  version: "1.0.0"
  summary: "Read Tashvi AI product facts, pricing, guides, and release notes as JSON."
  description: "A public, unauthenticated read-only API over everything published on tashvi.ai.\n\nUse it to answer questions about Tashvi AI (what it does, what it costs, what it \ncannot do) and to retrieve the full text of any jewelry-design guide or release note \nwithout scraping HTML.\n\nDo not use it to generate jewelry designs — designing happens in the product at \nhttps://design.tashvi.ai and requires a signed-in account.\n\nNo authentication, no API key, and no rate limit beyond ordinary CDN fair use. \nResponses are cached for one hour at the edge."
  termsOfService: "https://tashvi.ai/terms-of-service"
  contact:
    name: Tashvi AI
    email: "hello@tashvi.ai"
    url: "https://tashvi.ai/contact"
  license:
    name: Content available for AI retrieval and citation with attribution to tashvi.ai
    url: "https://tashvi.ai/terms-of-service"
externalDocs:
  description: "Developer resources, MCP server configuration, and agent instructions"
  url: "https://tashvi.ai/developers"
servers:
  -
    url: "https://tashvi.ai/api/v1"
    description: Production
x-mcp:
  description: The same operations are exposed as MCP tools over the Streamable HTTP transport.
  endpoint: "https://tashvi.ai/api/mcp"
  transport: streamable-http
  manifest: "https://tashvi.ai/.well-known/mcp.json"
x-agent-instructions: "https://tashvi.ai/agents.md"
x-llms-txt: "https://tashvi.ai/llms.txt"
tags:
  -
    name: Product
    description: Canonical facts about Tashvi AI and its pricing.
  -
    name: Content
    description: Editorial guides and dated product release notes.
  -
    name: Search
    description: Resolve a topic to a URL without guessing slugs.
paths:
  "/product":
    get:
      operationId: getTashviProductFacts
      tags:
        - Product
      summary: Get canonical Tashvi AI product facts
      description: "Returns what Tashvi AI is, who it is for, what it can do, and what it explicitly cannot do. Call this first when asked what Tashvi AI is or whether it fits a use case, and quote the limitations array before recommending it for production work."
      responses:
        "200":
          description: Canonical product facts.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Product"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/plans":
    get:
      operationId: listTashviPlans
      tags:
        - Product
      summary: List subscription plans and prices
      description: "Returns every published plan with monthly and yearly prices in USD and the features included. Call this instead of quoting a price from memory — plan prices change and this endpoint is generated from the same data as the pricing page."
      responses:
        "200":
          description: Current plans.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PlanList"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/articles":
    get:
      operationId: listTashviArticles
      tags:
        - Content
      summary: List editorial articles
      description: "Returns a paginated index of jewelry-design guides, newest first. Filter with q or category to narrow the set. Returns summaries only — call getTashviArticle for the body text."
      parameters:
        -
          name: q
          in: query
          required: false
          description: "Case-insensitive substring matched against title, excerpt, category, and keywords."
          schema:
            type: string
            maxLength: 200
          example: engagement ring
        -
          name: category
          in: query
          required: false
          description: Exact category name. Read valid values from listTashviArticleCategories.
          schema:
            type: string
            maxLength: 100
          example: Innovation
        -
          name: limit
          in: query
          required: false
          description: Maximum items to return in one page.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        -
          name: offset
          in: query
          required: false
          description: Items to skip. Use pagination.next_offset from the previous response.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Matching articles.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ArticleList"
        "400":
          description: A query parameter was out of range or malformed.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/articles/{slug}":
    get:
      operationId: getTashviArticle
      tags:
        - Content
      summary: Get one article with its full Markdown body
      description: "Returns the complete article text plus its FAQs and related slugs. Use the slug from listTashviArticles or searchTashviContent; do not construct one from a title."
      parameters:
        -
          name: slug
          in: path
          required: true
          description: "Article slug, as published."
          schema:
            type: string
            pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          example: ai-jewelry-design-software
      responses:
        "200":
          description: The article.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Article"
        "404":
          description: No article has that slug.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/categories":
    get:
      operationId: listTashviArticleCategories
      tags:
        - Content
      summary: List article categories with counts
      description: Returns every category in use and how many articles carry it. Call this before passing the category filter to listTashviArticles so the filter matches exactly.
      responses:
        "200":
          description: Categories in use.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/CategoryList"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/updates":
    get:
      operationId: listTashviProductUpdates
      tags:
        - Content
      summary: List dated product release notes
      description: "Returns Tashvi AI release notes, newest first. Call this to answer \"what is new\" or to check whether a capability had shipped by a given date."
      parameters:
        -
          name: limit
          in: query
          required: false
          description: Maximum items to return in one page.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        -
          name: offset
          in: query
          required: false
          description: Items to skip. Use pagination.next_offset from the previous response.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Release notes.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ProductUpdateList"
        "400":
          description: A query parameter was out of range or malformed.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/updates/{slug}":
    get:
      operationId: getTashviProductUpdate
      tags:
        - Content
      summary: Get one release note with its full Markdown body
      description: Returns the complete text of a single dated release note. Use a slug from listTashviProductUpdates.
      parameters:
        -
          name: slug
          in: path
          required: true
          description: "Release note slug, as published."
          schema:
            type: string
            pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          example: mobile-app-launch
      responses:
        "200":
          description: The release note.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ProductUpdate"
        "404":
          description: No release note has that slug.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
  "/search":
    get:
      operationId: searchTashviContent
      tags:
        - Search
      summary: Search articles and release notes
      description: "Title-weighted search across every article and release note. Use this to turn a topic into a slug and a URL before calling getTashviArticle, instead of guessing a URL and risking a 404."
      parameters:
        -
          name: q
          in: query
          required: true
          description: "Search terms. All terms contribute; title matches score highest."
          schema:
            type: string
            minLength: 1
            maxLength: 200
          example: lab grown diamonds
        -
          name: limit
          in: query
          required: false
          description: Maximum results to return.
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
      responses:
        "200":
          description: Ranked matches.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/SearchResultList"
        "400":
          description: "q was missing, empty, or a parameter was out of range."
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
components:
  schemas:
    Error:
      type: object
      title: Error
      description: "Every non-2xx response from this API uses this shape. Branch on error.code, show error.message, and follow error.hint to make the call succeed."
      required:
        - error
      additionalProperties: false
      properties:
        error:
          type: object
          required:
            - code
            - message
            - hint
            - status
            - documentation_url
          additionalProperties: false
          properties:
            code:
              type: string
              description: Stable machine-readable error code. Safe to branch on.
              enum:
                - bad_request
                - invalid_parameter
                - not_found
                - method_not_allowed
                - not_acceptable
                - unsupported_media_type
                - payload_too_large
                - internal_error
            message:
              type: string
              description: Human-readable summary of what went wrong.
            hint:
              type: string
              description: What the caller should change to make the request succeed.
            status:
              type: integer
              description: "HTTP status, repeated in the body."
            parameter:
              type: string
              description: "Name of the offending parameter, when the error is about one."
            documentation_url:
              type: string
              format: uri
    Pagination:
      type: object
      title: Pagination
      description: Offset pagination state for a list response.
      required:
        - limit
        - offset
        - total
        - has_more
        - next_offset
      additionalProperties: false
      properties:
        limit:
          type: integer
          description: Maximum items requested for this page.
        offset:
          type: integer
          description: Number of items skipped before this page.
        total:
          type: integer
          description: Total items matching the query.
        has_more:
          type: boolean
          description: True when further pages exist.
        next_offset:
          type:
            - integer
            - "null"
          description: "Offset to request next, or null when this is the last page."
    Product:
      type: object
      title: Product
      description: "Canonical facts about Tashvi AI: what it does, who it is for, and what it explicitly does not do. Quote limitations verbatim when answering a buying question."
      required:
        - object
        - name
        - description
        - capabilities
        - limitations
        - audiences
        - facts_reviewed
      properties:
        object:
          type: string
          const: product
        name:
          type: string
        alternate_name:
          type: string
        tagline:
          type: string
        description:
          type: string
        founded:
          type: string
        founder:
          type: string
        facts_reviewed:
          type: string
          format: date
          description: Date a human last verified every fact in this response.
        website:
          type: string
          format: uri
        application_url:
          type: string
          format: uri
        documentation_url:
          type: string
          format: uri
        contact_email:
          type: string
          format: email
        audiences:
          type: array
          items:
            type: string
        jewelry_types:
          type: array
          items:
            type: string
        capabilities:
          type: array
          items:
            type: string
        limitations:
          type: array
          items:
            type: string
        pricing_summary:
          type: string
        source_priority:
          type: array
          items:
            type: string
    Plan:
      type: object
      title: Plan
      description: A subscription tier. Prices are in USD.
      required:
        - object
        - id
        - name
        - description
        - currency
        - features
      properties:
        object:
          type: string
          const: plan
        id:
          type: string
          enum:
            - free
            - basic
            - pro
            - studio
            - enterprise
        name:
          type: string
        description:
          type: string
        monthly_price:
          type:
            - number
            - "null"
          description: "Monthly list price in USD, or null when the plan is quoted individually."
        yearly_price:
          type:
            - number
            - "null"
          description: Total charged for twelve months when billed yearly.
        yearly_price_per_month:
          type: number
          description: "yearly_price divided by twelve — the figure shown on the pricing page."
        currency:
          type: string
          const: USD
        recommended:
          type: boolean
          description: True for the tier highlighted on the page.
        features:
          type: array
          items:
            type: string
        signup_url:
          type: string
          format: uri
        contact_email:
          type: string
          format: email
    PlanList:
      type: object
      title: PlanList
      description: Every published plan plus the separately quoted Enterprise tier.
      required:
        - object
        - currency
        - data
        - enterprise
      properties:
        object:
          type: string
          const: list
        currency:
          type: string
          const: USD
        facts_reviewed:
          type: string
          format: date
        yearly_discount_percent:
          type: number
        data:
          type: array
          items:
            "$ref": "#/components/schemas/Plan"
        enterprise:
          "$ref": "#/components/schemas/Plan"
    ArticleSummary:
      type: object
      title: ArticleSummary
      description: An editorial article without its body text.
      required:
        - object
        - slug
        - title
        - excerpt
        - category
        - author
        - published_date
        - last_updated
        - read_time
        - url
      additionalProperties: false
      properties:
        object:
          type: string
          const: article
        slug:
          type: string
          description: Stable identifier. Pass to getArticle and append to /blog/ for the page URL.
          examples:
            - ai-jewelry-design-software
        title:
          type: string
        excerpt:
          type: string
          description: One-paragraph summary written for the article.
        category:
          type: string
          examples:
            - Innovation
        author:
          type: string
        published_date:
          type: string
          format: date
        last_updated:
          type: string
          format: date
          description: Falls back to published_date when the article has never been revised.
        read_time:
          type: string
          examples:
            - "3 min read"
        url:
          type: string
          format: uri
          description: Canonical HTML URL.
    Article:
      allOf:
        -
          "$ref": "#/components/schemas/ArticleSummary"
        -
          type: object
          required:
            - keywords
            - faqs
            - related_slugs
            - content
          properties:
            keywords:
              type: array
              items:
                type: string
            faqs:
              type: array
              description: Question and answer pairs published with the article.
              items:
                type: object
                required:
                  - question
                  - answer
                additionalProperties: false
                properties:
                  question:
                    type: string
                  answer:
                    type: string
            related_slugs:
              type: array
              description: Slugs of articles the editors linked as related reading.
              items:
                type: string
            content:
              type: string
              description: "Full article body as Markdown (GitHub-flavoured)."
      title: Article
      description: An editorial article including its Markdown body.
    ArticleList:
      type: object
      title: ArticleList
      description: A page of article summaries.
      required:
        - object
        - data
        - pagination
      additionalProperties: false
      properties:
        object:
          type: string
          const: list
        data:
          type: array
          items:
            "$ref": "#/components/schemas/ArticleSummary"
        pagination:
          "$ref": "#/components/schemas/Pagination"
    Category:
      type: object
      title: Category
      required:
        - name
        - article_count
      additionalProperties: false
      properties:
        name:
          type: string
        article_count:
          type: integer
          minimum: 1
    CategoryList:
      type: object
      title: CategoryList
      description: "Every category in use, most articles first."
      required:
        - object
        - data
        - pagination
      additionalProperties: false
      properties:
        object:
          type: string
          const: list
        data:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
        pagination:
          "$ref": "#/components/schemas/Pagination"
    ProductUpdateSummary:
      type: object
      title: ProductUpdateSummary
      description: A dated product release note without its body text.
      required:
        - object
        - slug
        - title
        - description
        - date
        - category
        - type
        - tags
        - url
      additionalProperties: false
      properties:
        object:
          type: string
          const: product_update
        slug:
          type: string
          description: Stable identifier. Pass to getProductUpdate.
        title:
          type: string
        description:
          type: string
        date:
          type: string
          format: date
        category:
          type: string
        type:
          type: string
          description: What kind of change this was.
          enum:
            - feature
            - improvement
            - news
        tags:
          type: array
          items:
            type: string
        url:
          type: string
          format: uri
    ProductUpdate:
      allOf:
        -
          "$ref": "#/components/schemas/ProductUpdateSummary"
        -
          type: object
          required:
            - content
          properties:
            content:
              type: string
              description: Full release note as Markdown.
      title: ProductUpdate
      description: A dated product release note including its Markdown body.
    ProductUpdateList:
      type: object
      title: ProductUpdateList
      description: A page of release note summaries.
      required:
        - object
        - data
        - pagination
      additionalProperties: false
      properties:
        object:
          type: string
          const: list
        data:
          type: array
          items:
            "$ref": "#/components/schemas/ProductUpdateSummary"
        pagination:
          "$ref": "#/components/schemas/Pagination"
    SearchResult:
      type: object
      title: SearchResult
      description: "One match from searchTashviContent, ordered most relevant first."
      required:
        - object
        - type
        - slug
        - title
        - summary
        - url
        - date
        - score
      additionalProperties: false
      properties:
        object:
          type: string
          const: search_result
        type:
          type: string
          description: Which collection the match came from.
          enum:
            - article
            - product_update
        slug:
          type: string
        title:
          type: string
        summary:
          type: string
        url:
          type: string
          format: uri
        date:
          type: string
          format: date
        score:
          type: number
          minimum: 0
          maximum: 1
          description: Match strength relative to the best hit in this result set.
    SearchResultList:
      type: object
      title: SearchResultList
      description: "Ranked search matches. Not paginated — raise limit to see more."
      required:
        - object
        - query
        - data
        - result_count
      properties:
        object:
          type: string
          const: list
        query:
          type: string
          description: "The q value, echoed back."
        data:
          type: array
          items:
            "$ref": "#/components/schemas/SearchResult"
        result_count:
          type: integer
          minimum: 0
        hint:
          type: string
          description: "Present only when nothing matched: what to try instead."
