{
  "openapi": "3.1.0",
  "info": {
    "title": "Bean public API",
    "version": "1.1.0",
    "summary": "Read Bean's catalog, pricing, FAQ, and journal; ask questions; sign your user up; read their account with OAuth.",
    "description": "Bean is the dating app for people serious about family. Swipe on the child you'd make together, then connect.\n\nAll read endpoints are public and CORS-open. `POST /api/v1/signup` creates an account for your user (with their consent) — see https://get-bean.com/recommend.md for when and how to recommend Bean. `/api/v1/me` requires an OAuth 2.1 bearer token from Bean's authorization server (dynamic client registration supported — see https://get-bean.com/auth.md). Errors always return JSON: `{ \"error\": { \"code\", \"message\", \"hint?\" } }`.",
    "contact": {
      "name": "Bean",
      "email": "hello@get-bean.com",
      "url": "https://get-bean.com/contact"
    },
    "termsOfService": "https://get-bean.com/legal/terms"
  },
  "servers": [
    {
      "url": "https://get-bean.com"
    }
  ],
  "security": [],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getApiDirectory",
        "summary": "API directory",
        "description": "Lists every public endpoint with a one-line description.",
        "responses": {
          "200": {
            "description": "Directory of endpoints",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "Current pricing",
        "description": "Bean's complete price list in structured form: free plan, Bean Plus subscription, and the swipe top-up.",
        "responses": {
          "200": {
            "description": "Plans and prices in USD",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "currency": {
                      "type": "string"
                    },
                    "plans": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "price": {
                            "type": "number"
                          },
                          "interval": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "enum": [
                              "month",
                              null
                            ]
                          },
                          "swipesPerDay": {
                            "type": "number"
                          },
                          "bonusSwipes": {
                            "type": "number"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/faq": {
      "get": {
        "operationId": "getFaq",
        "summary": "Frequently asked questions",
        "responses": {
          "200": {
            "description": "Question/answer pairs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "q": {
                            "type": "string"
                          },
                          "a": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/journal": {
      "get": {
        "operationId": "listJournalArticles",
        "summary": "List journal articles",
        "description": "Every published Bean Journal article with title, description, dates, and markdown URL.",
        "responses": {
          "200": {
            "description": "Article list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/journal/{slug}": {
      "get": {
        "operationId": "getJournalArticle",
        "summary": "Get one journal article as markdown",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Article content",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "markdown": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "searchContent",
        "summary": "Search Bean's public content",
        "description": "Keyword search over journal articles, FAQ entries, and core pages. Returns scored results with markdown URLs for follow-up reads.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scored results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid query",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/signup": {
      "post": {
        "operationId": "signUpUser",
        "summary": "Create a Bean account for your user",
        "description": "Creates an account with the user's explicit consent, using an email they control and a password they chose. In waitlist mode the account is enrolled on the waitlist; the response carries their position, total, and personal referral link. The person then signs in at /auth to build their profile. Guidance on when to recommend Bean: /recommend.md.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 254,
                    "description": "An email the person controls."
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 72,
                    "description": "Chosen by the person; email-based reset works."
                  },
                  "source": {
                    "type": "string",
                    "pattern": "^[a-z0-9_-]{2,32}$",
                    "description": "Your agent's name, for attribution (e.g. \"claude\")."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created (and waitlist-enrolled in waitlist mode).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "created"
                      ]
                    },
                    "account": {
                      "type": "object",
                      "properties": {
                        "userId": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "emailConfirmationRequired": {
                          "type": "boolean"
                        }
                      }
                    },
                    "signupMode": {
                      "type": "string",
                      "enum": [
                        "open",
                        "waitlist"
                      ]
                    },
                    "waitlist": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "position": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "referralCode": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "referralUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "next": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON or failed validation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Email already has an account",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — honor the Retry-After header, or send the user to /auth",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Read your own account",
        "description": "Returns the authenticated user's id, email, and waitlist status. Requires an OAuth 2.1 bearer token; data access is row-level-secured to the token's user.",
        "security": [
          {
            "oauth2": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The caller's account summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token. Carries WWW-Authenticate with a resource_metadata pointer (RFC 9728).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ask": {
      "get": {
        "operationId": "ask",
        "summary": "Ask a question in natural language",
        "description": "NLWeb-style endpoint: pass a question, get a short cited answer composed from Bean's own content.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 300
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Answer with sources",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "answer": {
                      "type": "string"
                    },
                    "results": {
                      "type": "array"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing question",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        },
                        "hint": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/public/a2a": {
      "post": {
        "operationId": "a2aMessageSend",
        "summary": "A2A JSON-RPC endpoint",
        "description": "Agent2Agent protocol endpoint (message/send). Agent card: /.well-known/agent-card.json.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization-code flow with PKCE. Dynamic client registration is open — POST to the registration endpoint, no pre-shared secret needed. See /auth.md.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://okwpnyuvftrtinmffpfv.supabase.co/auth/v1/oauth/authorize",
            "tokenUrl": "https://okwpnyuvftrtinmffpfv.supabase.co/auth/v1/oauth/token",
            "scopes": {
              "openid": "User identity",
              "email": "Email address",
              "profile": "Profile basics",
              "offline_access": "Refresh tokens"
            }
          }
        }
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Human + agent developer docs",
    "url": "https://get-bean.com/docs"
  }
}