{"openapi":"3.1.0","info":{"title":"HashtagLab API","description":"Hashtag generation API for social media optimization","version":"1.0.0"},"paths":{"/api/v1/auth/me":{"get":{"summary":"Get current user profile","description":"Return the authenticated user's profile, syncing with Clerk.","operationId":"get_me_api_v1_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthMeResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/auth/sync":{"post":{"summary":"Sync Clerk user to local DB","description":"Create or update the local MongoDB user record from Clerk session data.","operationId":"sync_user_api_v1_auth_sync_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthSyncResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/hashtags/generate":{"post":{"summary":"Generate hashtags","description":"Generate optimized hashtag sets for a topic and platform.","operationId":"generate_hashtags_api_v1_hashtags_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HashtagGenerateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HashtagGenerateResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/trends/{platform}":{"get":{"summary":"Get trending hashtags","description":"Retrieve trending hashtags for a specific platform.","operationId":"get_trends_api_v1_trends__platform__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrendsResponse"}}}},"400":{"description":"Invalid platform","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/platforms":{"get":{"summary":"List supported platforms","description":"Return all social media platforms supported by HashtagLab.","operationId":"get_platforms_api_v1_platforms_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformsResponse"}}}}}}},"/api/v1/categories":{"get":{"summary":"List hashtag categories","description":"Return all available hashtag categories.","operationId":"get_categories_api_v1_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoriesResponse"}}}}}}},"/api/v1/billing/pricing-plans":{"get":{"summary":"Get pricing plans","description":"Return cached pricing plans from Stripe or fallback cache.","operationId":"get_pricing_plans_api_v1_billing_pricing_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingPlansResponse"}}}}}}},"/api/v1/billing/create-checkout-session":{"post":{"summary":"Create checkout session","description":"Create a Stripe Checkout Session for the authenticated user.","operationId":"create_checkout_session_api_v1_billing_create_checkout_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Stripe or internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/create-portal-session":{"post":{"summary":"Create billing portal session","description":"Create a Stripe Billing Portal session for the authenticated user.","operationId":"create_portal_session_api_v1_billing_create_portal_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalSessionResponse"}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Stripe or internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/summary":{"get":{"summary":"Get billing summary","description":"Return billing summary for the authenticated user, or a free plan summary if unauthenticated.","operationId":"billing_summary_api_v1_billing_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/invoices":{"get":{"summary":"Get invoices (placeholder)","description":"**Internal placeholder** — full invoice history via Stripe Portal.","operationId":"billing_invoices_api_v1_billing_invoices_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-internal":true}},"/api/v1/billing/credit-packs":{"get":{"summary":"Get credit packs (placeholder)","description":"**Internal placeholder** — credit pack catalogue TBD.","operationId":"credit_packs_api_v1_billing_credit_packs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-internal":true}},"/api/v1/billing/buy-credits":{"post":{"summary":"Buy credits (placeholder)","description":"**Internal placeholder** — credit purchase flow TBD.","operationId":"buy_credits_api_v1_billing_buy_credits_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-internal":true}},"/api/v1/billing/create-user-profile":{"post":{"summary":"Create user profile","description":"Create Stripe customer profile for a user (called on signup).","operationId":"create_user_profile_api_v1_billing_create_user_profile_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/billing/webhook":{"post":{"summary":"Handle Stripe webhook","description":"Receive and process Stripe webhook events.","operationId":"stripe_webhook_api_v1_billing_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid payload or signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/api-keys":{"get":{"summary":"List API keys","description":"Return API keys for the current user.","operationId":"list_api_keys_api_v1_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/api-keys/generate":{"post":{"summary":"Generate new API key","description":"Generate a new API key for the current user.","operationId":"generate_api_key_api_v1_api_keys_generate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/api-keys/{key_id}":{"delete":{"summary":"Revoke API key","description":"Revoke an existing API key.","operationId":"revoke_api_key_api_v1_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api-keys/whitelist":{"get":{"summary":"Get IP whitelist","description":"Return the IP whitelist for the current user's API key.","operationId":"get_ip_whitelist_api_v1_api_keys_whitelist_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Set IP whitelist","description":"Set the IP whitelist for an API key.","operationId":"set_ip_whitelist_api_v1_api_keys_whitelist_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health Check","description":"Health check endpoint.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AuthMeResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Local database user ID"},"clerk_id":{"type":"string","title":"Clerk Id","description":"Clerk user identifier"},"email":{"type":"string","title":"Email","description":"User email address"},"name":{"type":"string","title":"Name","description":"User display name"}},"type":"object","required":["id","clerk_id","email","name"],"title":"AuthMeResponse","description":"Response schema for GET /auth/me.","examples":[{"clerk_id":"user_2cEi4k...","email":"user@example.com","id":"64f1a2b3c4d5e6f7a8b9c0d1","name":"Jane Doe"}]},"AuthSyncResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether sync succeeded","default":true},"user_id":{"type":"string","title":"User Id","description":"Local user ID after sync"}},"type":"object","required":["user_id"],"title":"AuthSyncResponse","description":"Response schema for POST /auth/sync.","examples":[{"success":true,"user_id":"64f1a2b3c4d5e6f7a8b9c0d1"}]},"BillingSummaryResponse":{"properties":{"customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer Id","description":"Stripe customer ID"},"email":{"type":"string","title":"Email","description":"User email address"},"has_subscription":{"type":"boolean","title":"Has Subscription","description":"Whether the user has an active subscription"},"subscription":{"$ref":"#/components/schemas/SubscriptionInfo","description":"Detailed subscription information"}},"type":"object","required":["email","has_subscription","subscription"],"title":"BillingSummaryResponse","description":"Response schema for GET /billing/summary.","examples":[{"customer_id":"cus_abc123","email":"user@example.com","has_subscription":true,"subscription":{"current_period_end":"2025-02-01T00:00:00Z","plan":"team","price_id":"price_pro_monthly","status":"active"}}]},"CategoriesResponse":{"properties":{"categories":{"items":{"$ref":"#/components/schemas/CategoryInfo"},"type":"array","title":"Categories","description":"List of available hashtag categories"}},"type":"object","required":["categories"],"title":"CategoriesResponse","description":"Response schema for GET /categories.","examples":[{"categories":[{"name":"Technology","slug":"tech"},{"name":"Business & Marketing","slug":"business"},{"name":"Fitness & Health","slug":"fitness"}]}]},"CategoryInfo":{"properties":{"name":{"type":"string","title":"Name","description":"Human-readable category name"},"slug":{"type":"string","title":"Slug","description":"Machine-readable category identifier"}},"type":"object","required":["name","slug"],"title":"CategoryInfo","description":"A hashtag category.","examples":[{"name":"Technology","slug":"tech"}]},"CheckoutRequest":{"properties":{"price_id":{"type":"string","title":"Price Id","description":"Stripe Price ID to checkout with"},"success_url":{"type":"string","title":"Success Url","description":"URL to redirect on successful payment"},"cancel_url":{"type":"string","title":"Cancel Url","description":"URL to redirect on cancelled payment"}},"type":"object","required":["price_id","success_url","cancel_url"],"title":"CheckoutRequest","description":"Request schema for creating a checkout session.","examples":[{"cancel_url":"https://hashtaglab.app/checkout/cancel","price_id":"price_pro_monthly","success_url":"https://hashtaglab.app/checkout/success"}]},"CheckoutSessionResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"Stripe Checkout Session ID"},"url":{"type":"string","title":"Url","description":"URL to redirect the user for checkout"}},"type":"object","required":["session_id","url"],"title":"CheckoutSessionResponse","description":"Response schema for POST /billing/create-checkout-session.","examples":[{"session_id":"cs_test_abc123...","url":"https://checkout.stripe.com/c/cs_test_abc123..."}]},"ErrorResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Always False for errors","default":false},"error":{"type":"string","title":"Error","description":"Error message"},"code":{"type":"integer","title":"Code","description":"HTTP status code"}},"type":"object","required":["error","code"],"title":"ErrorResponse","description":"Error response schema.","examples":[{"code":400,"error":"Topic must be at least 2 characters","success":false}]},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HashtagGenerateRequest":{"properties":{"topic":{"type":"string","maxLength":100,"minLength":2,"title":"Topic","description":"Main topic/keyword"},"platform":{"type":"string","enum":["instagram","twitter","linkedin","tiktok"],"title":"Platform","description":"Target social media platform","default":"instagram"},"niche":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Niche","description":"Specific niche category"}},"type":"object","required":["topic"],"title":"HashtagGenerateRequest","description":"Request schema for hashtag generation.","examples":[{"niche":"gym","platform":"instagram","topic":"fitness"}]},"HashtagGenerateResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether generation succeeded","default":true},"relevant":{"items":{"$ref":"#/components/schemas/HashtagItem"},"type":"array","title":"Relevant","description":"Medium-competition hashtags"},"related":{"items":{"$ref":"#/components/schemas/HashtagItem"},"type":"array","title":"Related","description":"Low-competition (niche) hashtags"},"trending":{"items":{"$ref":"#/components/schemas/HashtagItem"},"type":"array","title":"Trending","description":"High-competition trending hashtags"},"generated_at":{"type":"string","format":"date-time","title":"Generated At","description":"UTC timestamp of generation"},"platform":{"type":"string","title":"Platform","description":"Platform the hashtags were generated for"},"topic":{"type":"string","title":"Topic","description":"Original topic requested"}},"type":"object","required":["platform","topic"],"title":"HashtagGenerateResponse","description":"Response schema for hashtag generation.","examples":[{"generated_at":"2025-01-01T00:00:00Z","platform":"instagram","related":[{"category":"fitness","competition":"low","tag":"#gymlife","volume":22000000}],"relevant":[{"category":"fitness","competition":"medium","tag":"#fitnessmotivation","volume":45000000}],"success":true,"topic":"fitness","trending":[{"category":"trending","competition":"high","tag":"#trending","volume":120000000}]}]},"HashtagItem":{"properties":{"tag":{"type":"string","title":"Tag","description":"The hashtag string, including leading #"},"volume":{"type":"integer","title":"Volume","description":"Estimated monthly search volume","default":0},"competition":{"type":"string","enum":["low","medium","high"],"title":"Competition","description":"Competition level","default":"medium"},"category":{"type":"string","title":"Category","description":"Hashtag category","default":"general"}},"type":"object","required":["tag"],"title":"HashtagItem","description":"Individual hashtag with metadata.","examples":[{"category":"fitness","competition":"high","tag":"#fitness","volume":220000000}]},"PlanFeatures":{"properties":{"team":{"type":"boolean","title":"Team","description":"Team collaboration access","default":false},"leaves":{"type":"boolean","title":"Leaves","description":"Leave management","default":false},"timesheet":{"type":"boolean","title":"Timesheet","description":"Time tracking","default":false},"api":{"type":"boolean","title":"Api","description":"API access","default":false},"multiple_orgs":{"type":"boolean","title":"Multiple Orgs","description":"Multiple orgs support","default":false},"unlimited_date_range":{"type":"boolean","title":"Unlimited Date Range","description":"Unlimited date range","default":false},"max_users":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Users","description":"Maximum number of users"},"max_orgs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Orgs","description":"Maximum number of orgs"},"date_range_months":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Date Range Months","description":"Date range in months"},"max_api_keys":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Api Keys","description":"Maximum API keys"}},"type":"object","title":"PlanFeatures","description":"Feature flags for a pricing plan."},"PlatformInfo":{"properties":{"name":{"type":"string","title":"Name","description":"Human-readable platform name"},"slug":{"type":"string","title":"Slug","description":"Machine-readable platform identifier"},"max_hashtags":{"type":"integer","title":"Max Hashtags","description":"Maximum hashtags recommended for this platform"},"icon":{"type":"string","title":"Icon","description":"Icon identifier"}},"type":"object","required":["name","slug","max_hashtags","icon"],"title":"PlatformInfo","description":"Information about a supported platform.","examples":[{"icon":"camera","max_hashtags":30,"name":"Instagram","slug":"instagram"}]},"PlatformsResponse":{"properties":{"platforms":{"items":{"$ref":"#/components/schemas/PlatformInfo"},"type":"array","title":"Platforms","description":"List of supported platforms"}},"type":"object","required":["platforms"],"title":"PlatformsResponse","description":"Response schema for GET /platforms.","examples":[{"platforms":[{"icon":"camera","max_hashtags":30,"name":"Instagram","slug":"instagram"},{"icon":"bird","max_hashtags":3,"name":"Twitter","slug":"twitter"},{"icon":"briefcase","max_hashtags":5,"name":"LinkedIn","slug":"linkedin"},{"icon":"music","max_hashtags":10,"name":"TikTok","slug":"tiktok"}]}]},"PortalRequest":{"properties":{"return_url":{"type":"string","title":"Return Url","description":"URL to return to after portal session"}},"type":"object","required":["return_url"],"title":"PortalRequest","description":"Request schema for creating a billing portal session.","examples":[{"return_url":"https://hashtaglab.app/billing"}]},"PortalSessionResponse":{"properties":{"url":{"type":"string","title":"Url","description":"URL to redirect the user for the billing portal"}},"type":"object","required":["url"],"title":"PortalSessionResponse","description":"Response schema for POST /billing/create-portal-session.","examples":[{"url":"https://billing.stripe.com/p/login/..."}]},"PricingPlan":{"properties":{"product_id":{"type":"string","title":"Product Id","description":"Stripe product ID"},"name":{"type":"string","title":"Name","description":"Plan display name"},"description":{"type":"string","title":"Description","description":"Plan description","default":""},"type":{"type":"string","title":"Type","description":"Plan type: free, team, addon, lifetime"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Product metadata"},"features":{"$ref":"#/components/schemas/PlanFeatures","description":"Plan features"},"prices":{"items":{"$ref":"#/components/schemas/PricingPlanPrice"},"type":"array","title":"Prices","description":"Available price options"},"active":{"type":"boolean","title":"Active","description":"Whether the plan is active","default":true},"created":{"type":"integer","title":"Created","description":"Unix timestamp of creation","default":0}},"type":"object","required":["product_id","name","type","features"],"title":"PricingPlan","description":"A single pricing plan from Stripe or fallback cache.","examples":[{"active":true,"created":0,"description":"Basic hashtag generation","features":{"api":false,"max_api_keys":0},"metadata":{},"name":"HashtagLab Free","prices":[{"amount":0,"currency":"EUR","id":"price_free","interval":"month","interval_count":1,"metadata":{},"type":"recurring"}],"product_id":"prod_free","type":"free"}]},"PricingPlanPrice":{"properties":{"id":{"type":"string","title":"Id","description":"Stripe price ID"},"amount":{"type":"integer","title":"Amount","description":"Price amount in cents"},"currency":{"type":"string","title":"Currency","description":"ISO currency code"},"interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interval","description":"Billing interval (month/year)"},"interval_count":{"type":"integer","title":"Interval Count","description":"Multiplier for the interval","default":1},"type":{"type":"string","title":"Type","description":"Price type: recurring or one_time","default":"recurring"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Price metadata"}},"type":"object","required":["id","amount","currency"],"title":"PricingPlanPrice","description":"A price option within a pricing plan."},"PricingPlansResponse":{"properties":{"plans":{"items":{"$ref":"#/components/schemas/PricingPlan"},"type":"array","title":"Plans","description":"List of available pricing plans"}},"type":"object","required":["plans"],"title":"PricingPlansResponse","description":"Response schema for GET /billing/pricing-plans.","examples":[{"plans":[{"active":true,"created":0,"description":"Basic hashtag generation","features":{"api":false,"max_api_keys":0},"metadata":{},"name":"HashtagLab Free","prices":[{"amount":0,"currency":"EUR","id":"price_free","interval":"month","interval_count":1,"metadata":{},"type":"recurring"}],"product_id":"prod_free","type":"free"}]}]},"SubscriptionInfo":{"properties":{"plan":{"type":"string","title":"Plan","description":"Subscription plan type","default":"free"},"status":{"type":"string","title":"Status","description":"Subscription status","default":"none"},"price_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Id","description":"Stripe price ID"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End","description":"End of the current billing period"}},"type":"object","title":"SubscriptionInfo","description":"Subscription information for a user."},"TrendsResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the request succeeded","default":true},"platform":{"type":"string","title":"Platform","description":"Platform the trends are for"},"hashtags":{"items":{"$ref":"#/components/schemas/HashtagItem"},"type":"array","title":"Hashtags","description":"List of trending hashtags"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When the trends were last updated"}},"type":"object","required":["platform","hashtags","updated_at"],"title":"TrendsResponse","description":"Response schema for trends.","examples":[{"hashtags":[{"category":"trending","competition":"high","tag":"#trending","volume":120000000}],"platform":"instagram","success":true,"updated_at":"2025-01-01T00:00:00Z"}]},"UserProfileResponse":{"properties":{"message":{"type":"string","title":"Message","description":"Success message"},"clerk_id":{"type":"string","title":"Clerk Id","description":"Clerk user ID"},"stripe_customer_id":{"type":"string","title":"Stripe Customer Id","description":"Created Stripe customer ID"}},"type":"object","required":["message","clerk_id","stripe_customer_id"],"title":"UserProfileResponse","description":"Response schema for POST /billing/create-user-profile.","examples":[{"clerk_id":"user_2cEi4k...","message":"ok","stripe_customer_id":"cus_abc123"}]},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookResponse":{"properties":{"received":{"type":"boolean","title":"Received","description":"Whether the webhook was received"}},"type":"object","required":["received"],"title":"WebhookResponse","description":"Response schema for POST /billing/webhook.","examples":[{"received":true}]}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}