{
  "openapi": "3.1.0",
  "info": {
    "title": "Plurel public API",
    "version": "1.0.0",
    "summary": "Read-only facts and news about Plurel, for AI agents and developers.",
    "description": "Plurel is building the future of social finance: one card a whole group funds before the purchase. This API returns what plurelinc.com publishes: company facts, products, team and news. It needs no authentication and is read-only. Every response carries rate-limit headers (60 requests per 60 seconds per network, IETF RateLimit header fields); a 429 also carries Retry-After. Errors are JSON objects with a machine-readable code, a message and a hint. Any page on plurelinc.com is also available as Markdown: request it with Accept: text/markdown, or add .md to its path.",
    "contact": {
      "name": "Plurel",
      "email": "contact@plurelinc.com",
      "url": "https://plurelinc.com/contact"
    },
    "termsOfService": "https://plurelinc.com/terms"
  },
  "externalDocs": {
    "description": "Plurel public API documentation",
    "url": "https://plurelinc.com/developers"
  },
  "servers": [
    {
      "url": "https://plurelinc.com",
      "description": "Production"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Company",
      "description": "Who Plurel is."
    },
    {
      "name": "News",
      "description": "Posts published on plurelinc.com/news."
    }
  ],
  "paths": {
    "/api/v1/company": {
      "get": {
        "operationId": "getCompany",
        "tags": [
          "Company"
        ],
        "summary": "Get facts about Plurel",
        "description": "Returns Plurel's description, location, contact details, products, how it works, team and useful links. Use it to answer questions about the company.",
        "responses": {
          "200": {
            "description": "Company facts.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. Wait for Retry-After seconds.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/news": {
      "get": {
        "operationId": "listNews",
        "tags": [
          "News"
        ],
        "summary": "List published news posts",
        "description": "Returns every published post on plurelinc.com/news, newest first, with title, summary, date, author and links. Fetch one post's full text with getNewsPost.",
        "responses": {
          "200": {
            "description": "Published posts.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "posts"
                  ],
                  "properties": {
                    "posts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NewsSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. Wait for Retry-After seconds.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/news/{slug}": {
      "get": {
        "operationId": "getNewsPost",
        "tags": [
          "News"
        ],
        "summary": "Get one news post",
        "description": "Returns one published post with its body in Markdown. The slug comes from listNews or from the post's URL (plurelinc.com/news/{slug}).",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The post's slug: lowercase letters, numbers and hyphens.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,80}$",
              "examples": [
                "pre-seed-closed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The post.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NewsPost"
                }
              }
            }
          },
          "400": {
            "description": "The slug isn't valid.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No published post has that slug.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. Wait for Retry-After seconds.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimit": {
        "description": "Remaining quota and seconds until reset, e.g. \"default\";r=59;t=42 (draft-ietf-httpapi-ratelimit-headers).",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Policy": {
        "description": "The quota, e.g. \"default\";q=60;w=60.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "On 429: seconds to wait before retrying.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "hint",
              "status",
              "docs"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "not_found",
                  "invalid_request",
                  "rate_limited",
                  "method_not_allowed",
                  "internal_error"
                ],
                "description": "Machine-readable error code."
              },
              "message": {
                "type": "string",
                "description": "What went wrong."
              },
              "hint": {
                "type": "string",
                "description": "How to fix the request."
              },
              "status": {
                "type": "integer",
                "description": "The HTTP status code."
              },
              "docs": {
                "type": "string",
                "format": "uri",
                "description": "Where the API is documented."
              }
            }
          }
        }
      },
      "Company": {
        "type": "object",
        "required": [
          "name",
          "legalName",
          "url",
          "description",
          "location",
          "email",
          "products",
          "team"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "legalName": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string"
          },
          "mission": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "address": {
            "type": "object",
            "properties": {
              "streetAddress": {
                "type": "string"
              },
              "addressLocality": {
                "type": "string"
              },
              "addressRegion": {
                "type": "string"
              },
              "postalCode": {
                "type": "string"
              },
              "addressCountry": {
                "type": "string"
              }
            }
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "programs": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "howItWorks": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "products": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "audience",
                "points",
                "status"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "audience": {
                  "type": "string"
                },
                "points": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "status": {
                  "type": "string"
                }
              }
            }
          },
          "team": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "role",
                "bio"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "role": {
                  "type": "string"
                },
                "bio": {
                  "type": "string"
                },
                "linkedin": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      },
      "NewsSummary": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "summary",
          "category",
          "url",
          "markdownUrl"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "author": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "role": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "markdownUrl": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "NewsPost": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NewsSummary"
          },
          {
            "type": "object",
            "required": [
              "bodyMarkdown"
            ],
            "properties": {
              "bodyMarkdown": {
                "type": "string",
                "description": "The post's body in Markdown, links made absolute."
              }
            }
          }
        ]
      }
    }
  }
}