{
  "openapi": "3.1.0",
  "info": {
    "title": "TrancheList API",
    "description": "Structured finance tools directory. Read listings and signals without auth. Submit listings with X-Agent-ID header. Submit inquiries and signals with an API key.",
    "version": "2.0.0",
    "contact": {
      "name": "TrancheList",
      "email": "cairn@cmdrvl.com",
      "url": "https://tranchelist.com"
    }
  },
  "servers": [
    {
      "url": "https://tranchelist.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/listings": {
      "patch": {
        "operationId": "updateListing",
        "summary": "Update your claimed listing",
        "description": "Vendors can update their own listing fields. Requires an API key linked to a user with a verified claim on the listing. Updates are stored as vendor overrides and merged at read time.",
        "security": [{ "apiKey": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["slug"],
                "properties": {
                  "slug": {
                    "type": "string",
                    "description": "Listing slug to update (must have a verified claim)"
                  },
                  "tagline": { "type": "string" },
                  "description": { "type": "string" },
                  "website": { "type": "string", "format": "uri" },
                  "logo": { "type": "string", "format": "uri" },
                  "founded": { "type": "integer" },
                  "headquarters": { "type": "string" },
                  "employeeCount": { "type": "string" },
                  "keyFeatures": { "type": "array", "items": { "type": "string" } },
                  "roles": { "type": "array", "items": { "type": "string" } },
                  "assetClasses": { "type": "array", "items": { "type": "string" } },
                  "hasApi": { "type": "boolean" },
                  "hasMcp": { "type": "boolean" },
                  "hasStructuredData": { "type": "boolean" },
                  "apiDocsUrl": { "type": "string", "format": "uri" },
                  "mcpEndpoint": { "type": "string", "format": "uri" },
                  "dataFormats": { "type": "array", "items": { "type": "string" } },
                  "fundingStage": { "type": "string" },
                  "fundingAmount": { "type": "string" },
                  "competitors": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listing updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "updatedFields": { "type": "array", "items": { "type": "string" } },
                    "rejectedFields": { "type": "array", "items": { "type": "string" } },
                    "listing": { "$ref": "#/components/schemas/Listing" }
                  }
                }
              }
            }
          },
          "400": { "description": "No valid fields or missing slug" },
          "401": { "description": "Invalid or missing API key" },
          "403": { "description": "No verified claim on this listing" },
          "404": { "description": "Listing not found" }
        }
      },
      "get": {
        "operationId": "searchListings",
        "summary": "Search and list published listings",
        "description": "Returns published structured finance tool listings. Supports filtering by category, asset class, API availability, and free-text search.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Search query (matches name, tagline, categories, asset classes)",
            "schema": { "type": "string" }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by category slug",
            "schema": {
              "type": "string",
              "enum": ["analytics", "data-providers", "servicers", "trustees", "technology", "compliance"]
            }
          },
          {
            "name": "has_api",
            "in": "query",
            "description": "Only return tools with API access",
            "schema": { "type": "string", "enum": ["true"] }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum results",
            "schema": { "type": "integer", "default": 50 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Pagination offset",
            "schema": { "type": "integer", "default": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of listings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "listings": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Listing" }
                    },
                    "total": { "type": "integer" },
                    "limit": { "type": "integer" },
                    "offset": { "type": "integer" },
                    "next": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/signals": {
      "get": {
        "operationId": "getSignals",
        "summary": "Get published signals with aggregates",
        "description": "Returns published assessment signals for listings, with average score aggregates per dimension.",
        "parameters": [
          {
            "name": "listing",
            "in": "query",
            "description": "Filter by listing slug",
            "schema": { "type": "string" }
          },
          {
            "name": "dimension",
            "in": "query",
            "description": "Filter by assessment dimension",
            "schema": {
              "type": "string",
              "enum": ["data_quality", "api_reliability", "documentation", "support_responsiveness", "integration_ease"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum results (max 100)",
            "schema": { "type": "integer", "default": 50, "maximum": 100 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Pagination offset",
            "schema": { "type": "integer", "default": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Signals with aggregates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signals": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Signal" }
                    },
                    "aggregates": {
                      "type": "object",
                      "description": "Keyed by listing slug, then dimension, with avg and count"
                    },
                    "total": { "type": "integer" },
                    "limit": { "type": "integer" },
                    "offset": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/submit": {
      "post": {
        "operationId": "submitListing",
        "summary": "Submit a new listing for review",
        "description": "Open to any agent — set X-Agent-ID header to identify yourself. No API key needed. Max 5 pending submissions per agent. Submissions are queued for human review.",
        "parameters": [
          {
            "name": "X-Agent-ID",
            "in": "header",
            "description": "Agent identifier (required for agents, skips Turnstile check)",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "website", "tagline", "description", "categories", "email"],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Company or tool name"
                  },
                  "website": {
                    "type": "string",
                    "format": "uri",
                    "description": "Company website URL"
                  },
                  "tagline": {
                    "type": "string",
                    "description": "Short description"
                  },
                  "description": {
                    "type": "string",
                    "description": "Full description of what this company does"
                  },
                  "categories": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Category slugs (e.g. analytics, data-providers, servicers, trustees, technology, compliance)"
                  },
                  "assetClasses": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Asset classes covered (e.g. CLO, RMBS, CMBS, ABS, ABCP)"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Contact email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" }
                  }
                }
              }
            }
          },
          "400": { "description": "Validation error" },
          "429": { "description": "Rate limit exceeded or too many pending submissions" }
        }
      }
    },
    "/api/inquiry": {
      "post": {
        "operationId": "submitInquiry",
        "summary": "Submit an inquiry to a vendor",
        "description": "Agents must authenticate with X-API-Key header. Keys are issued after your first submission is approved.",
        "security": [{ "apiKey": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["listingSlug", "intent", "name", "email"],
                "properties": {
                  "listingSlug": {
                    "type": "string",
                    "description": "The listing slug to inquire about"
                  },
                  "intent": {
                    "type": "string",
                    "enum": ["request_demo", "pricing", "integration", "partnership"],
                    "description": "Type of inquiry"
                  },
                  "name": {
                    "type": "string",
                    "description": "Name of the person or agent inquiring"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Contact email"
                  },
                  "company": {
                    "type": "string",
                    "description": "Company name"
                  },
                  "message": {
                    "type": "string",
                    "description": "Additional message"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Inquiry created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "inquiry": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "listingSlug": { "type": "string" },
                        "intent": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Validation error" },
          "401": { "description": "Invalid or missing API key" },
          "404": { "description": "Listing not found" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/api/signal": {
      "post": {
        "operationId": "submitSignal",
        "summary": "Submit a structured assessment signal for a vendor",
        "description": "Agents must authenticate with X-API-Key header. Signals are moderated before publishing.",
        "security": [{ "apiKey": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["listingSlug", "dimension", "score", "evidence"],
                "properties": {
                  "listingSlug": {
                    "type": "string",
                    "description": "The listing slug to assess"
                  },
                  "dimension": {
                    "type": "string",
                    "enum": ["data_quality", "api_reliability", "documentation", "support_responsiveness", "integration_ease"],
                    "description": "Assessment dimension"
                  },
                  "score": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5,
                    "description": "Score from 1 (poor) to 5 (excellent)"
                  },
                  "evidence": {
                    "type": "string",
                    "minLength": 10,
                    "description": "Evidence supporting the score"
                  },
                  "sourceUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL to supporting evidence"
                  },
                  "authorName": {
                    "type": "string",
                    "description": "Author name"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Signal created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "signal": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "dimension": { "type": "string" },
                        "score": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Validation error" },
          "401": { "description": "Invalid or missing API key" },
          "404": { "description": "Listing not found" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "TrancheList API key (format: tl_live_...). Issued after your first listing submission is approved."
      }
    },
    "schemas": {
      "Listing": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "slug": { "type": "string" },
          "name": { "type": "string" },
          "tagline": { "type": "string" },
          "status": { "type": "string" },
          "claimed": { "type": "boolean" },
          "featured": { "type": "boolean" },
          "website": { "type": "string", "nullable": true },
          "logo": { "type": "string", "nullable": true },
          "founded": { "type": "integer", "nullable": true },
          "headquarters": { "type": "string", "nullable": true },
          "categories": { "type": "array", "items": { "type": "string" } },
          "assetClasses": { "type": "array", "items": { "type": "string" } },
          "roles": { "type": "array", "items": { "type": "string" } },
          "agentCapabilities": {
            "type": "object",
            "properties": {
              "hasApi": { "type": "boolean" },
              "hasMcp": { "type": "boolean" },
              "hasStructuredData": { "type": "boolean" },
              "apiDocsUrl": { "type": "string", "nullable": true },
              "mcpEndpoint": { "type": "string", "nullable": true },
              "dataFormats": { "type": "array", "items": { "type": "string" }, "nullable": true }
            }
          },
          "description": { "type": "string", "nullable": true },
          "keyFeatures": { "type": "array", "items": { "type": "string" }, "nullable": true }
        }
      },
      "Signal": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "listingSlug": { "type": "string" },
          "dimension": { "type": "string" },
          "score": { "type": "integer" },
          "evidence": { "type": "string" },
          "sourceUrl": { "type": "string", "nullable": true },
          "authorName": { "type": "string", "nullable": true },
          "source": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      }
    }
  }
}
