{"message":"Welcome to the Partner Bio API!","description":"This API provides endpoints for managing user signups, admin operations, and beta code generation for the Partner Bio platform.","endpoints":[{"method":"GET","path":"/","description":"API introduction and documentation."},{"method":"POST","path":"/v1/app-feedback","description":"Notifies the team Slack channel that in-app feedback was submitted. Requires authentication and JSON body with a valid 'feedbackId'. Slack failures do not fail the request.","authentication":"Required - Bearer token","requestBody":{"feedbackId":"string (required, uuid of the app_feedback row)"}},{"method":"POST","path":"/v1/content-reports","description":"Notifies the team Slack channel that a UGC report was submitted. Requires authentication and JSON body with a valid 'reportId'. Slack failures do not fail the request.","authentication":"Required - Bearer token","requestBody":{"reportId":"string (required, uuid of the content_reports row)"}},{"method":"POST","path":"/v1/webhooks/sendgrid/inbound-parse","description":"Receives SendGrid Inbound Parse raw MIME for @partner.bio, stores a copy in Supabase, and notifies Slack. Authenticate with the token query parameter. Slack and storage failures do not fail the request after the row is saved. Duplicates (same Message-ID) return 200 without a second Slack message.","authentication":"Required - token query parameter (SENDGRID_INBOUND_PARSE_SECRET)","requestBody":{"email":"string (required, raw full MIME message)","from":"string (optional fallback)","to":"string (optional fallback)","subject":"string (optional fallback)","envelope":"string (optional JSON)","spam_score":"string (optional)"}},{"method":"POST","path":"/v1/notifications/email/dispatch","description":"Machine-to-machine notification email dispatcher. Loads a notifications row, maps type to a SendGrid template, checks email prefs, and sends. Skips meeting.* and message.received. Always 200 after auth so pg_net does not retry.","authentication":"Required - X-Push-Secret matching SUPABASE_SERVICE_ROLE_KEY","requestBody":{"notification_id":"string (required, uuid of the notifications row)"}},{"method":"POST","path":"/v1/messages/email/dispatch","description":"Machine-to-machine message email sender. Resolves conversation recipients and sends the Message Received template when email_messages is enabled.","authentication":"Required - X-Push-Secret matching SUPABASE_SERVICE_ROLE_KEY","requestBody":{"message_id":"string (required, uuid of the messages row)"}},{"method":"POST","path":"/v1/email/weekly-digest","description":"Machine-to-machine weekly digest job. Sends the previous calendar week digest to eligible users. Idempotent via email_digest_sends.","authentication":"Required - X-Push-Secret matching SUPABASE_SERVICE_ROLE_KEY","requestBody":{"user_id":"string (optional, limit the run to one user)"}},{"method":"POST","path":"/v1/webhooks/supabase/send-email","description":"Supabase Auth Send Email Hook. Verifies the Standard Webhooks signature, maps email_action_type to a branded SendGrid template, and sends the message. Keep the Auth email provider enabled. Slack is not used.","authentication":"Required - Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature) using SEND_EMAIL_HOOK_SECRET","requestBody":{"user":"object (required, Auth user including email and user_metadata)","email_data":"object (required, token_hash, email_action_type, redirect_to, and optional token_hash_new)"}},{"method":"POST","path":"/v1/auth/password-reset","description":"Sends a branded password-reset email. Looks up the account and creates a recovery link with the service role, then sends the AUTH_RESET_PASSWORD SendGrid template. Does not call the public Auth /recover endpoint.","authentication":"Not required","requestBody":{"email":"string (required)","redirectTo":"string (optional, must be an app.partner.bio / test.partner.bio / localhost reset-password URL)"},"responseExample":{"success":true}},{"method":"POST","path":"/v1/signup-request","description":"Handles a signup request submitted by a user on the application. Requires JSON body with a valid 'requestID'."},{"method":"POST","path":"/v1/create-account","description":"Creates a confirmed Auth user with the service role (no confirmation email), then writes public.users and consumes the invite code. Requires JSON body with email, password, name, and inviteCode."},{"method":"POST","path":"/v1/analyze-image","description":"Analyzes images using AI. Requires JSON body with image data."},{"method":"POST","path":"/v1/organizations/enrich-from-domain","description":"Enriches organization create-form fields from a company website via the GCF worker. Requires authentication (Bearer token). Rate limited per user per day.","authentication":"Required - Bearer token","requestBody":{"website":"string (required, max 2048 chars)","force_refresh":"boolean (optional, default false)"},"headers":{"X-Request-Id":"optional UUID; echoed on response if valid"},"responseExample":{"success":true,"exists":false,"fields":{"name":"Acme Biotech"},"meta":{"request_id":"uuid","latency_ms":4100}}},{"method":"POST","path":"/v1/organizations/:id/bootstrap-matching","description":"Seeds org-level partnership intent and initial AI partner matches after company creation. Requires org Owner/Manager role. Returns 202 with run_id for polling.","authentication":"Required - Bearer token","requestBody":{"force_refresh":"boolean (optional, default false)","skip_if_intent_exists":"boolean (optional, default true)"},"responseExample":{"success":true,"run_id":"uuid","status":"running","intent_status":"pending","poll_url":"/v1/matches/status/uuid"}},{"method":"POST","path":"/v1/matches/partners/evaluate","description":"Evaluates platform users, organizations, and personal contacts for complementary partnership fit. Requires authentication.","authentication":"Required - Bearer token","requestBody":{"context":"{ entity_type: 'user' | 'organization', entity_id: string | null }","force_refresh":"boolean (optional)","include_personal_contacts":"boolean (optional)","include_platform_users":"boolean (optional)","include_platform_organizations":"boolean (optional)"}},{"method":"POST","path":"/v1/matches/opportunities/generate","description":"Evaluates published opportunities against the user's partnership intent. Requires authentication.","authentication":"Required - Bearer token","requestBody":{"force_refresh":"boolean (optional)"}},{"method":"POST","path":"/v1/matches/generate","description":"Convenience endpoint that runs partner and/or opportunity match generation. Requires authentication.","authentication":"Required - Bearer token","requestBody":{"scope":"('partners' | 'opportunities')[]","force_refresh":"boolean (optional)"}},{"method":"GET","path":"/v1/matches/status/:run_id","description":"Returns match_generation_runs status for polling async generation jobs. Requires authentication.","authentication":"Required - Bearer token"},{"method":"POST","path":"/v1/send-email","description":"Sends emails via SendGrid. Requires JSON body with emailData, dynamicTemplateData, and templateId."},{"method":"POST","path":"/v1/export-user-data","description":"Exports all user data in GDPR-compliant format. Requires authentication (Bearer token) and JSON body with userId, deliveryMethod ('email' or 'download'), and email (if deliveryMethod is 'email').","authentication":"Required - Bearer token","requestBody":{"userId":"string (UUID)","deliveryMethod":"'email' | 'download' (default: 'download')","email":"string (required if deliveryMethod is 'email')"},"responseExample":{"success":true,"deliveryMethod":"email","estimatedDeliveryTime":"5-10 minutes","metadata":{"dataSize":"2.4 MB","recordCount":1523,"exportId":"uuid"}}},{"method":"DELETE","path":"/v1/account","description":"Starts async deletion of the authenticated user's account and associated data. User id is taken from the Bearer token; the body is ignored. Returns 202 with a request payload for polling. Rate limited to 3 requests per 24 hours. Returns 409 if the user is the sole owner of an organization. Successful self-service deletion triggers a non-blocking Slack notification to the signups channel.","authentication":"Required - Bearer token","responseExample":{"success":true,"accepted":true,"request_id":"uuid","status":"pending","current_step":"queued","poll_url":"/v1/account/delete-status","message":"Account deletion started."}},{"method":"GET","path":"/v1/account/delete-status","description":"Returns the authenticated user's latest account deletion request for progress polling. Requires authentication. Rate limited separately from DELETE /v1/account.","authentication":"Required - Bearer token","responseExample":{"success":true,"request_id":"uuid","status":"running","current_step":"removing_data","poll_url":"/v1/account/delete-status","message":"Account deletion in progress."}},{"method":"POST","path":"/v1/send-2fa-code","description":"Generates and sends a 6-digit 2FA code via email. Requires authentication (Bearer token) and 2FA must be enabled for the user. Rate limited to 3 requests per 15 minutes.","authentication":"Required - Bearer token","requestBody":{"userId":"string (UUID, required) - Must match authenticated user","email":"string (required) - User's email address","purpose":"'login' | 'password_change' | 'email_change' | 'account_recovery' (required)","ipAddress":"string (optional) - Client IP address for logging","userAgent":"string (optional) - Client user agent for logging"},"responseExample":{"success":true,"message":"2FA code sent successfully","data":{"userId":"550e8400-e29b-41d4-a716-446655440000","email":"u***@example.com","purpose":"login","expiresAt":"2024-01-01T12:05:00.000Z","expiresInSeconds":300}}},{"method":"POST","path":"/v1/verify-2fa-code","description":"Validates a 2FA code and marks it as used. Requires authentication (Bearer token). Rate limited to 5 failed attempts per 15 minutes. Codes expire after 5 minutes.","authentication":"Required - Bearer token","requestBody":{"userId":"string (UUID, required) - Must match authenticated user","code":"string (required) - 6-digit verification code","purpose":"'login' | 'password_change' | 'email_change' | 'account_recovery' (required)"},"responseExample":{"success":true,"message":"2FA code verified successfully","data":{"userId":"550e8400-e29b-41d4-a716-446655440000","purpose":"login","verifiedAt":"2024-01-01T12:03:00.000Z"}}},{"method":"POST","path":"/v1/integrations/outlook/exchange","description":"Exchanges Outlook OAuth authorization code for access token and account information. Requires Bearer token authentication and JSON body with authorization code and redirectUri (must match the URI used in the Microsoft authorize request).","authentication":"Required - Bearer token","requestBody":{"code":"string (required) - OAuth authorization code from Outlook","redirectUri":"string (required) - Redirect URI used in the authorize request (e.g. https://app.partner.bio/integrations/outlook/callback)"},"responseExample":{"success":true,"account_email":"user@example.com"}},{"method":"POST","path":"/v1/meetings/slots","description":"Returns bookable meeting slots for a host (working hours, bookings, Google/Outlook busy). Supports anonymous callers for public_global event types.","authentication":"Optional - Bearer token (user or anon key)","requestBody":{"hostUserId":"string (UUID, required)","eventTypeId":"string (UUID, optional)","eventTypeSlug":"string (optional)","useDefaultBookingSettings":"boolean (optional)","durationMinutes":"number (optional)","startDate":"ISO-8601 string (optional)","days":"number (optional)","inlineEventType":"object (optional, authenticated internal flows)"}},{"method":"POST","path":"/v1/meetings/slots/validate","description":"Validates a single slot before booking. Returns 409 when unavailable.","authentication":"Optional - Bearer token (user or anon key)","requestBody":{"hostUserId":"string (UUID, required)","startAt":"ISO-8601 string (required)","endAt":"ISO-8601 string (required)","eventTypeId":"string (UUID, optional)","eventTypeSlug":"string (optional)","useDefaultBookingSettings":"boolean (optional)","durationMinutes":"number (optional)"}},{"method":"POST","path":"/admin/delete-user","description":"Deletes a user and all associated data using the same cleanup as DELETE /v1/account. Requires admin authentication (Bearer token) and JSON body with user_id. Returns 409 if the user is the sole owner of an organization.","authentication":"Required - Bearer token (admin only)","requestBody":{"user_id":"string (UUID, required)"}},{"method":"POST","path":"/admin/users/send-auth-email","description":"Sends a branded recovery or magic-link email via generateLink, then the matching SendGrid template. Requires admin authentication. Rate limited to 50 requests per hour per admin.","authentication":"Required - Bearer token (admin only)","requestBody":{"email":"string (required)","type":"recovery | magiclink (required)","redirectTo":"string (optional)"}},{"method":"POST","path":"/admin/invite-user","description":"Sends an invitation to a user. Requires admin authentication (Bearer token) and JSON body with invite_id.","authentication":"Required - Bearer token (admin only)","requestBody":{"invite_id":"string (required)"}},{"method":"POST","path":"/admin/generate-codes","description":"Generates beta codes in bulk. Requires admin authentication (Bearer token) and JSON body with quantity.","authentication":"Required - Bearer token (admin only)","requestBody":{"quantity":"number (required) - Number of beta codes to generate"}},{"method":"POST","path":"/admin/signup-request/approve","description":"Approves a pending signup request. Requires admin authentication (Bearer token) and JSON body with request_id.","authentication":"Required - Bearer token (admin only)","requestBody":{"request_id":"string (required)"}},{"method":"POST","path":"/admin/signup-request/reject","description":"Rejects a pending signup request. Requires admin authentication (Bearer token) and JSON body with requestID.","authentication":"Required - Bearer token (admin only)","requestBody":{"requestID":"string (required)"}},{"method":"POST","path":"/admin/get-sessions","description":"Retrieves user sessions from the auth schema with pagination. Requires admin authentication (Bearer token) and JSON body with start_date, optional page_offset and page_size.","authentication":"Required - Bearer token (admin only)","requestBody":{"start_date":"string (required) - Start date for session query","page_offset":"number (optional, default: 0)","page_size":"number (optional, default: 10)"}},{"method":"POST","path":"/admin/create-dns-verification","description":"Creates a DNS verification record for domain verification. Requires admin authentication (Bearer token) and JSON body with domain.","authentication":"Required - Bearer token (admin only)","requestBody":{"domain":"string (required)"}},{"method":"POST","path":"/admin/verify-dns-record","description":"Verifies a DNS record for domain verification. Requires admin authentication (Bearer token) and JSON body with domain and verificationCode.","authentication":"Required - Bearer token (admin only)","requestBody":{"domain":"string (required)","verificationCode":"string (required)"}},{"method":"GET","path":"/admin/verify-dns-record/status/:domain","description":"Gets the DNS verification status for a domain. Requires admin authentication (Bearer token). Domain is provided as a path parameter.","authentication":"Required - Bearer token (admin only)","pathParameters":{"domain":"string (required) - Domain name to check verification status"}},{"method":"GET","path":"/v1/rss/fetch","description":"App Engine Cron RSS ingest trigger. Requires X-Appengine-Cron: true from 0.1.0.1. Awaits ingest and returns the fetch summary.","authentication":"Required - X-Appengine-Cron (GAE Cron) or X-Rss-Cron-Secret"},{"method":"POST","path":"/v1/rss/fetch","description":"Machine-to-machine RSS ingest trigger. Secured by X-Rss-Cron-Secret (RSS_CRON_SECRET or SUPABASE_SERVICE_ROLE_KEY). Awaits ingest and returns the fetch summary.","authentication":"Required - X-Rss-Cron-Secret header","requestBody":{"source_id":"string (optional UUID) - fetch a single source"}},{"method":"GET","path":"/admin/rss-sources","description":"Lists RSS/Atom sources and last fetch status. Requires admin authentication.","authentication":"Required - Bearer token (admin only)"},{"method":"POST","path":"/admin/rss-sources","description":"Creates an RSS/Atom source. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"name":"string (required)","feed_url":"string (required, http(s))","category":"international | fda | us_publisher","homepage_url":"string (optional)","is_active":"boolean (optional, default true)","show_in_insights":"boolean (optional, default true)"}},{"method":"POST","path":"/admin/rss-sources/fetch","description":"Fetches active RSS/Atom sources now and upserts items. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"source_id":"string (optional UUID)"}},{"method":"POST","path":"/admin/rss-sources/:id/enrich-image","description":"Scrapes the publisher homepage for up to 3 logo candidates and ranks them with vision for a source thumbnail. Does not persist; admin confirms in the UI. Optional homepage_url overrides the stored homepage. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"homepage_url":"string (optional http(s))"}},{"method":"POST","path":"/admin/rss-sources/:id/import-image","description":"Downloads an http(s) image URL into Storage (images/rss-sources/:id) and sets image_url. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"url":"string (required http(s))"}},{"method":"POST","path":"/admin/rss-sources/:id/upload-image","description":"Uploads image bytes into Storage (images/rss-sources/:id) and sets image_url. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"data":"string (required base64)","content_type":"string (optional)","file_name":"string (optional)"}},{"method":"PATCH","path":"/admin/rss-sources/:id","description":"Updates an RSS source (name, url, category, is_active, show_in_insights, image_url). Requires admin authentication.","authentication":"Required - Bearer token (admin only)"},{"method":"DELETE","path":"/admin/rss-sources/:id","description":"Deletes an RSS source and cascaded items. Requires admin authentication.","authentication":"Required - Bearer token (admin only)"},{"method":"GET","path":"/admin/rss-items","description":"Paginated ingested RSS items for moderation. Query: page_offset, page_size, source_id, is_published, search.","authentication":"Required - Bearer token (admin only)"},{"method":"POST","path":"/admin/rss-items/classify","description":"AI-classifies ingested RSS items that have no insights_type_id. Does not overwrite existing types. Optional source_id and limit (default 50, max 100).","authentication":"Required - Bearer token (admin only)","requestBody":{"source_id":"string (optional UUID)","limit":"number (optional, 1-100, default 50)"}},{"method":"PATCH","path":"/admin/rss-items/:id","description":"Sets is_published and/or insights_type_id on an ingested RSS item. Requires admin authentication.","authentication":"Required - Bearer token (admin only)","requestBody":{"is_published":"boolean (optional)","insights_type_id":"uuid or null (optional)"}},{"method":"POST","path":"/admin/organization-role-requests/:id/decision","description":"Makes a decision (approve/reject) on an organization role request. Requires admin authentication (Bearer token), request ID as path parameter, and JSON body with status, optional note and title.","authentication":"Required - Bearer token (admin only)","pathParameters":{"id":"string (required) - Organization role request ID"},"requestBody":{"status":"string (required) - Decision status","note":"string (optional)","title":"string (optional)"}}],"usage":"For most endpoints, send JSON requests and expect JSON responses. Admin endpoints require appropriate authentication and domain access. See documentation for details."}