{
  "openapi": "3.0.3",
  "info": {
    "title": "Caus Citation Check API",
    "version": "1.0.0",
    "description": "Public API for checking whether the sources behind a claim or AI answer are independent or the same story echoed.\n\nThis endpoint runs a conservative TypeScript-only TF-IDF / text-overlap echo grouping. It is an evidence-structure read, not a truth judgment.\n\nCaveats:\n- Not a truth verdict — does not judge whether any claim or source is correct.\n- Not human-reviewed validation — groupings are not labeled or checked by a human reviewer.\n- Not provenance or ownership lineage — measures same-event/echo independence only.\n- Not an accuracy receipt — conservative public implementation; no accuracy is claimed beyond Caus's existing receipt gates.",
    "contact": {
      "name": "Caus",
      "url": "https://caus.live"
    }
  },
  "servers": [
    {
      "url": "https://caus.live",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/citation-check": {
      "post": {
        "operationId": "citationCheck",
        "summary": "Check citation independence / echo grouping",
        "description": "Send 2–10 cited source excerpts. Returns which sources are independent vs. repeated echo of the same event. Conservative TF-IDF only; semantic-feature and hybrid modes are dev/evaluation-only and are rejected. `claim` is optional context: it is echoed back and included in the exported report, but never affects grouping.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "citations"
                ],
                "properties": {
                  "claim": {
                    "type": "string",
                    "description": "Optional context for the check (a claim, report excerpt, or AI answer). Echoed back in the response and included in the exported report, but NOT used to group sources. Omit or send an empty string when not needed.",
                    "maxLength": 2000
                  },
                  "citations": {
                    "type": "array",
                    "description": "Array of cited sources. 2–10 usable citations (with both title and excerpt) are required.",
                    "minItems": 2,
                    "maxItems": 10,
                    "items": {
                      "type": "object",
                      "required": [
                        "title",
                        "excerpt"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "Optional citation identifier."
                        },
                        "title": {
                          "type": "string",
                          "maxLength": 500,
                          "description": "Citation headline (required)."
                        },
                        "source": {
                          "type": "string",
                          "description": "Publisher or source name (optional)."
                        },
                        "url": {
                          "type": "string",
                          "maxLength": 2000,
                          "description": "Source URL (optional; Caus does not fetch it)."
                        },
                        "excerpt": {
                          "type": "string",
                          "maxLength": 5000,
                          "description": "Cited text or excerpt (required). Paste manually."
                        }
                      }
                    }
                  },
                  "strategy": {
                    "type": "string",
                    "enum": [
                      "tfidf"
                    ],
                    "default": "tfidf",
                    "description": "Echo-detection strategy. Only \"tfidf\" (conservative) is supported publicly."
                  },
                  "threshold": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 1,
                    "default": 0.55,
                    "description": "Similarity threshold for echo grouping. Default 0.55."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Citation independence result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "claim": {
                      "type": "string"
                    },
                    "providedCount": {
                      "type": "integer"
                    },
                    "independentCount": {
                      "type": "integer",
                      "description": "Number of independent evidence groups."
                    },
                    "duplicatesRemoved": {
                      "type": "integer",
                      "description": "Sources grouped as repeated echo."
                    },
                    "independenceRatio": {
                      "type": "number"
                    },
                    "largestEchoGroup": {
                      "type": "integer"
                    },
                    "sourceDiversity": {
                      "type": "string"
                    },
                    "strategy": {
                      "type": "string"
                    },
                    "strategyLabel": {
                      "type": "string"
                    },
                    "strategyTier": {
                      "type": "string"
                    },
                    "isDemoOnly": {
                      "type": "boolean"
                    },
                    "dedupThreshold": {
                      "type": "number"
                    },
                    "productionNote": {
                      "type": "string"
                    },
                    "clusters": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "cluster_id": {
                            "type": "integer"
                          },
                          "size": {
                            "type": "integer"
                          },
                          "avg_similarity": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Average pairwise TF-IDF similarity within the group (null for a standalone source)."
                          },
                          "strongest_similarity": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Strongest pairwise TF-IDF similarity within the group (null for a standalone source)."
                          },
                          "group_kind": {
                            "type": "string",
                            "enum": [
                              "repeated_echo",
                              "standalone"
                            ],
                            "description": "Whether this group is a repeated-echo group or a standalone independent source."
                          },
                          "explanation": {
                            "type": "string",
                            "description": "Source-independence receipt detail explaining why these citations were grouped. Not a truth or accuracy claim."
                          },
                          "representative_title": {
                            "type": "string"
                          },
                          "sources": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "articles": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "title": {
                                  "type": "string"
                                },
                                "source": {
                                  "type": "string"
                                },
                                "url": {
                                  "type": "string"
                                },
                                "publishedAt": {
                                  "type": "string"
                                },
                                "relevance_score": {
                                  "type": [
                                    "number",
                                    "null"
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error (structured).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "error",
                    "code"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable error message."
                    },
                    "code": {
                      "type": "string",
                      "description": "Machine-readable error code.",
                      "enum": [
                        "INVALID_JSON",
                        "INVALID_CLAIM",
                        "CLAIM_TOO_LONG",
                        "INVALID_CITATIONS",
                        "TOO_FEW_CITATIONS",
                        "TOO_MANY_CITATIONS",
                        "TITLE_TOO_LONG",
                        "EXCERPT_TOO_LONG",
                        "URL_TOO_LONG",
                        "UNSUPPORTED_STRATEGY",
                        "INVALID_THRESHOLD"
                      ]
                    },
                    "field": {
                      "type": "string",
                      "description": "Optional field path that caused the error."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string",
                      "const": "INTERNAL_ERROR"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
