# keyword-analysis-api > Agent-first keyword analysis API for live SERP research, page scraping, and keyword synthesis. ## Summary This service is designed for LLMs and MCP-style agents that need to: - create an account without a traditional website flow - verify ownership of an email with a one-time code - run live keyword analysis against Google results - receive structured SEO-oriented output focused on word count and keyword density - defer billing setup until after free usage is exhausted The product is mostly headless. Human interaction is only required for: - reading the email verification code - completing hosted Stripe billing setup when free usage is exhausted ## Authentication Flow 1. `POST /auth/create-account` Create or resume a pending account for an email address. 2. `POST /auth/verify-account` Submit the one-time code sent by email. On success this returns an API token. 3. Use the API token as either: - `Authorization: Bearer ` - `X-API-Key: ` ## Primary Endpoint ### `POST /keyword-analysis/analyze` Queue a keyword analysis job that will: - fetch live SERP results from Bright Data - scrape the top results with Jina Reader - calculate suggested target word count - score primary and supporting keyword candidates from the ranking-page corpus - recommend the closest ranking-backed primary keyword for the user's original query - use a constrained LLM cleanup pass to choose the strongest supporting keywords from those candidates - calculate primary and secondary keyword density targets from the ranking-page corpus #### Input ```json { "keyword": "ai teaching assistant", "top_n_results": 5, "include_page_content": false } ``` #### Output Returns: - `keyword` - `suggested_word_count` - `total_results_analyzed` - `results` - `analysis.primary_keyword` - `analysis.primary_keyword_density` - `analysis.secondary_keywords` Notes: - `keyword` is the user's original query - `analysis.primary_keyword` is the recommended ranking-backed primary keyword target - `results` contains only the pages actually used in the analysis and each item includes `analysis_rank` ## OpenAPI Summary ### Auth - `POST /auth/create-account` - `POST /auth/verify-account` - `GET /auth/account-status` - `GET /auth/usage-summary` ### Billing - `POST /billing/start-billing-setup` - `POST /billing/stripe/webhooks` - `GET /billing/setup/success` - `GET /billing/setup/cancel` ### Keyword Analysis - `POST /keyword-analysis/analyze` ### Discovery - `GET /` - `GET /llms.txt` - `GET /.well-known/llms.txt` - `GET /openapi.json` ## Account and Billing Endpoints ### `GET /auth/account-status` Get verified status, billing status, and free-search availability. ### `GET /auth/usage-summary` Get free usage, paid usage, successful searches, and failed searches. ### `POST /billing/start-billing-setup` Return a hosted Stripe URL for payment-method setup or billing management. ### `POST /billing/stripe/webhooks` Stripe webhook endpoint for billing state updates. ## Example Flows ### 1. Create Account Request: ```json { "email": "user@example.com" } ``` Response: ```json { "pending_user_id": "pending_abcd1234", "verification_required": true, "expires_in_seconds": 600, "delivery_method": "smtp" } ``` In development, `delivery_method` may be `console` and `verification_code` may be included directly. ### 2. Verify Account Request: ```json { "pending_user_id": "pending_abcd1234", "code": "123456" } ``` Response: ```json { "account_id": 1, "email": "user@example.com", "api_token": "kaa_xxxxx", "billing_status": "unconfigured", "free_searches_remaining": 25 } ``` ### 3. Check Account Status Response: ```json { "account_id": 1, "email": "user@example.com", "email_verified": true, "billing_configured": false, "billing_status": "unconfigured", "free_searches_remaining": 25, "paid_usage_enabled": false, "usage_this_month": 0 } ``` ### 4. Run Keyword Analysis Request: ```json { "keyword": "ai teaching assistant", "top_n_results": 5, "include_page_content": false } ``` Response shape: ```json { "keyword": "auto body repair pearland tx", "suggested_word_count": 550, "total_results_analyzed": 4, "results": [ { "analysis_rank": 1, "title": "Collision Repair in Pearland", "url": "https://example.com/pearland-collision-repair", "rank": 1, "word_count": 612, "scrape_error": null } ], "analysis": { "primary_keyword": "collision repair pearland", "primary_keyword_density": { "keyword": "collision repair pearland", "occurrence_count": 4, "occurrences_per_result": 1.0, "total_word_count": 2287, "density_percentage": 0.17 }, "secondary_keywords": [ { "keyword": "collision repair", "occurrence_count": 13, "occurrences_per_result": 3.25, "total_word_count": 2287, "density_percentage": 0.57 } ] } } ``` ### 5. Start Billing Setup Response: ```json { "billing_status": "unconfigured", "url": "https://checkout.stripe.com/...", "mode": "checkout_setup", "stripe_customer_id": "cus_123" } ``` ## Billing-Required Response Pattern When free usage is exhausted and billing is not configured, the API may return HTTP `402` with a detail object like: ```json { "message": "Billing setup required", "billing_url": "https://checkout.stripe.com/..." } ``` ## Billing Model - First 25 successful searches are free - Billing is only required after free usage is exhausted - Failed searches should not be billed - Successful searches are metered per completed keyword-analysis request ## Agent Guidance - If account creation returns a verification code in development, use it directly - In production, ask the human to check email for the code - If analysis returns a billing-required response, show the hosted billing URL to the user - Prefer `top_n_results=5` unless a larger competitive sample is necessary - Use `include_page_content=false` by default to minimize payload size ## Best Practices For Agents - Treat `create-account` and `verify-account` as a two-step handshake - Do not retry verification blindly after a wrong code; ask the user to re-check email - Store the returned API token securely for future calls - On HTTP `402`, pause analysis flow and present the hosted billing URL to the human - Retry transient upstream failures conservatively; avoid repeated search bursts - Do not assume every SERP request will return the same ranking set across time and geography - Treat `analysis.primary_keyword` as the recommended target and `keyword` as the user's original query - Use `account-status` before prompting the user for billing if you are unsure whether free usage remains - Consider `usage-summary` the source of truth for agent-side quota messaging - Default to 5 results for speed and cost unless the user explicitly asks for deeper analysis - If partial scraping occurs but a valid analysis returns, treat the request as successful unless the API says otherwise ## Discovery Endpoints - `GET /` - `GET /llms.txt` - `GET /.well-known/llms.txt` - `GET /openapi.json` ## Notes - This service is optimized for fast, structured keyword analysis rather than broad SEO suite workflows - It is intended to be easier and cheaper to use than a full SEO platform when the only need is quick live keyword research