Base URL: https://app.geoleaper.com/api

Geoleaper API v2.2

Analyze and optimize your web pages for AI visibility using our template-based scoring system. Generate LLMS.txt files with AI-powered content analysis.

Authentication

The Geoleaper API uses Laravel Sanctum for token-based authentication. All API endpoints (except token creation) require a valid Bearer token.

Obtaining an API Token

Generate a new API token by providing your account credentials:

Request

curl -X POST https://app.geoleaper.com/api/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "email": "your@email.com",
    "password": "your_password",
    "token_name": "my-app-token"
  }'

Response

200 OK
{
  "token": "1|abc123...",
  "token_name": "my-app-token",
  "login_url": "https://geoleaper.com/login-as/...",
  "tenant": {
    "id": 1,
    "name": "My Company"
  },
  "user": {
    "id": 1,
    "name": "John Doe",
    "email": "your@email.com"
  }
}
Important: Save your token securely. It will only be shown once and cannot be retrieved later.

Using Your Token

Include your API token in the Authorization header with the Bearer prefix:

curl https://app.geoleaper.com/api/analyses \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json"

Token Management

List All Tokens

GET /auth/tokens

Revoke Current Token

DELETE /auth/tokens/current

Revoke All Tokens

DELETE /auth/tokens/all
Best Practices:
  • Use descriptive token names to identify different applications or environments
  • Store tokens securely using environment variables or secret management systems
  • Rotate tokens regularly for enhanced security
  • Revoke tokens immediately if compromised

Quick Start

1. Get Your API Token

curl -X POST https://app.geoleaper.com/api/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "email": "your@email.com",
    "password": "your_password"
  }'

2. Create Analysis

curl -X POST https://app.geoleaper.com/api/analyses \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/product"}'

3. Poll for Results

curl https://app.geoleaper.com/api/analyses/{id} \
  -H "Authorization: Bearer YOUR_API_TOKEN"
Analysis runs asynchronously in the background. Poll every 2-5 seconds until status is completed.

Package Limits

Package
Max Unique URLs
Max Domains
Bulk Limit
FREE
10 1 10 URLs
PRO
200 1 200 URLs
MAX
1,500 5 1,500 URLs
Note: There are currently no rate limits (requests per minute) enforced on API endpoints. The limits above refer to the maximum number of unique URLs and domains you can analyze based on your plan.

Analyses Endpoints

GET
/analyses

Retrieve paginated list of analyses with optional URL filtering.

Query Parameters

Parameter
Type
Required
Description
url string No Filter by URL (partial match)
per_page integer No Results per page (default: 20, max: 100)

Example Request

curl "https://app.geoleaper.com/api/analyses?url=example.com&per_page=10"

Response

200 OK
{
  "data": [
    {
      "id": 7,
      "url": "https://example.com/product",
      "score": 90,
      "status": "completed",
      "created_at": "2025-11-02T09:16:28+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 10,
    "total": 45
  }
}
Lightweight Response: The list endpoint returns only essential fields (id, url, score, status, created_at). Use the GET /analyses/{id} endpoint to retrieve full analysis details including score breakdown, issues, and suggestions.
POST
/analyses

Create a new analysis job. Returns immediately with analysis ID. The analysis runs asynchronously in the background queue.

Request Body

{
  "url": "https://example.com/product"
}

Response

202 Accepted
{
  "id": 7,
  "url": "https://example.com/product",
  "status": "pending",
  "check_url": "https://app.geoleaper.com/api/analyses/7",
  "created_at": "2025-11-02T09:16:28+00:00"
}
Store the check_url and poll it every 2-5 seconds until the analysis is complete.
POST
/analyses/bulk

Create multiple analyses from a sitemap.xml file. Supports sitemap index files and nested sitemaps.

Request Body

{
  "sitemap_url": "https://example.com/sitemap.xml",
  "limit": 50
}

Parameters

Parameter
Type
Required
Description
sitemap_url string Yes URL to sitemap.xml file
limit integer No Max URLs to analyze (default: 100, max: 1000)

Response

202 Accepted
{
  "message": "Bulk analysis started",
  "total": 50,
  "analyses": [
    {
      "id": 10,
      "url": "https://example.com/page1",
      "status": "pending",
      "check_url": "https://app.geoleaper.com/api/analyses/10"
    }
  ]
}
GET
/analyses/{id}

Get analysis status and results. Poll this endpoint to check if analysis is complete.

Response States

Pending/Processing
200 OK
{
  "id": 7,
  "url": "https://example.com/product",
  "status": "analyzing",
  "message": "Fetching and analyzing page content",
  "created_at": "2025-11-02T09:16:28+00:00"
}
Completed (Full Response)
200 OK
{
  "id": 7,
  "url": "https://example.com/product",
  "status": "completed",
  "score": {
    "total": 90,
    "grade": "A",
    "breakdown": {
      "schema_coverage": {
        "score": 25,
        "max": 25,
        "percentage": 100,
        "description": "Policy Compliance - Single primary Organization, logo dimensions, URL consistency"
      },
      "schema_integrity": {
        "score": 25,
        "max": 25,
        "percentage": 100,
        "description": "Data Completeness - Required fields for page type"
      },
      "entity_clarity": {
        "score": 25,
        "max": 25,
        "percentage": 100,
        "description": "Entity Disambiguation - BreadcrumbList, sameAs, @id consistency"
      },
      "ai_readability": {
        "score": 15,
        "max": 25,
        "percentage": 60,
        "description": "Source Credibility - ContactPoint, Organization ownership"
      }
    },
    "criteria_details": {
      "total_score": 90,
      "max_score": 100,
      "implemented_max_score": 95,
      "percentage": 90,
      "sections": { ... },
      "evidence": { ... }
    }
  },
  "page_type": "article",
  "page_type_info": {
    "detected_type": "article",
    "schema_type": "article",
    "detection_method": "ollama"
  },
  "issues": [],
  "suggestions": [],
  "improvements": [
    {
      "category": "AI Readability",
      "current_score": 15,
      "max_score": 25,
      "missing_points": 10,
      "description": "Add author.name or publisher.name, datePublished"
    }
  ],
  "json_ld_blocks": [...],
  "perfect_json_ld": null,
  "recommended_html_changes": {
    "top_prompts": [
      {
        "prompt": "What are the best practices for AI-driven search optimization?",
        "prompt_id": 123,
        "match_score": 0.95,
        "html_changes": [
          {
            "location": "After article introduction",
            "action": "add",
            "content_text": "AI-driven search optimization requires a focus on semantic relevance and structured data to help search engines understand your content.",
            "html_element": "p",
            "html_code": "

AI-driven search optimization requires a focus on semantic relevance and structured data to help search engines understand your content.

", "reason": "This content directly addresses the prompt about AI search best practices and adds topical authority" }, { "location": "Before conclusion", "action": "add", "content_text": "Key techniques include implementing comprehensive schema markup, optimizing for entity recognition, and creating content that answers specific user questions.", "html_element": "h3", "html_code": "

Key AI Optimization Techniques

Key techniques include implementing comprehensive schema markup, optimizing for entity recognition, and creating content that answers specific user questions.

", "reason": "Provides actionable insights that strengthen the page's relevance for AI search optimization queries" } ] }, { "prompt": "How to improve website visibility in ChatGPT and Perplexity?", "prompt_id": 124, "match_score": 0.87, "html_changes": [ { "location": "FAQ section", "action": "add", "content_text": "To improve visibility in AI-powered search engines like ChatGPT and Perplexity, ensure your content includes clear headings, concise answers, and proper schema markup.", "html_element": "FAQ schema", "html_code": "

How can I improve my site's visibility in ChatGPT?

Focus on creating well-structured content with clear headings, comprehensive information, and proper schema markup to help AI systems understand your content.

", "reason": "FAQ schema helps AI engines extract precise answers while providing users with valuable information" } ] } ], "total_prompts_analyzed": 23, "token_usage": { "prompt": 4521, "completion": 1834, "total": 6355, "cost": 0.0501 } }, "metadata": {...}, "created_at": "2025-11-02T09:16:28+00:00", "updated_at": "2025-11-02T09:16:35+00:00" }
Failed
500 Internal Server Error
{
  "id": 7,
  "url": "https://example.com/invalid",
  "status": "failed",
  "error": "Could not fetch the webpage: Connection timeout",
  "created_at": "2025-11-02T09:16:28+00:00"
}

LLMS.txt Generation

Overview

The LLMS.txt Generation feature uses AI to automatically create optimized llms.txt files for your website. The AI analyzes your website content, discovers important pages, and generates a comprehensive llms.txt file that helps AI systems better understand your business.

Availability: This feature is only available for Pro and Max plans. Free plan users will receive a 403 error when attempting to generate llms.txt files.

3 per month

Generation limit for all plans

~2-5 min

Average generation time

5-10 pages

Content sources analyzed

How It Works

1
Content Discovery

The AI fetches your homepage and identifies important pages (about, pricing, features, documentation, etc.)

2
Content Extraction

Scrapes and analyzes content from your homepage and up to 4 additional important pages

3
AI Generation

Uses GPT-4o to analyze the content and generate a comprehensive, structured llms.txt file in English

4
Optimization

The generated file is optimized for AI understanding with clear structure, concrete information, and scannable formatting

GET
/llms-txt

Retrieve paginated list of llms.txt generations for your tenant.

Query Parameters

Parameter
Type
Required
Description
per_page integer No Results per page (default: 20, max: 100)

Response

200 OK
{
  "data": [
    {
      "id": 1,
      "url": "https://example.com",
      "status": "completed",
      "created_at": "2025-11-20T10:00:00+00:00",
      "generated_at": "2025-11-20T10:02:15+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "total": 1
  }
}
POST
/llms-txt

Create a new llms.txt generation job. The AI will browse your website and create a comprehensive llms.txt file. This process runs asynchronously and typically takes 2-5 minutes.

Request Body

{
  "url": "https://example.com"
}

Response

202 Accepted
{
  "id": 1,
  "url": "https://example.com",
  "status": "pending",
  "message": "LLMS.txt generation started. Check status using the provided check_url.",
  "check_url": "https://app.geoleaper.com/api/llms-txt/1",
  "created_at": "2025-11-20T10:00:00+00:00"
}

Error Responses

403 Forbidden

Feature not available (Free plan):

{
  "message": "LLMS.txt generation is only available for Pro and Max plans.",
  "error": "upgrade_required"
}
429 Too Many Requests

Rate limit exceeded:

{
  "message": "Monthly generation limit reached. You can generate up to 3 llms.txt files per month.",
  "error": "rate_limit_exceeded",
  "usage": {
    "generations_used": 3,
    "generations_limit": 3,
    "generations_remaining": 0,
    "can_generate": false
  }
}
Poll the check_url every 30 seconds until the status is completed or failed.
GET
/llms-txt/{id}

Check the status of an llms.txt generation and retrieve the content when completed.

Response States

Pending/Generating
200 OK
{
  "id": 1,
  "url": "https://example.com",
  "status": "generating",
  "message": "Generation in progress. Please check back in a moment.",
  "created_at": "2025-11-20T10:00:00+00:00"
}

Statuses: pending (queued) or generating (AI processing)

Completed
200 OK
{
  "id": 1,
  "url": "https://example.com",
  "status": "completed",
  "content": "# Company Name\\n\\n> One-line value proposition...\\n\\n...",
  "created_at": "2025-11-20T10:00:00+00:00",
  "generated_at": "2025-11-20T10:02:15+00:00"
}

The content field contains the complete llms.txt file content ready to use.

Failed
200 OK
{
  "id": 1,
  "url": "https://example.com",
  "status": "failed",
  "error": "OpenAI API request failed: ...",
  "created_at": "2025-11-20T10:00:00+00:00"
}
GET
/llms-txt/{id}/download

Download the generated llms.txt content as a plain text file.

Response

200 OK

Returns plain text file with Content-Disposition: attachment; filename="llms.txt"

Error Responses

400 Bad Request

Generation not completed yet

404 Not Found

Generation not found

Example

curl https://app.geoleaper.com/api/llms-txt/1/download \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -o llms.txt
GET
/llms-txt/usage

Get current month's usage statistics for llms.txt generation.

Response (Pro/Max Plans)

200 OK
{
  "has_access": true,
  "usage": {
    "generations_used": 2,
    "generations_limit": 3,
    "generations_remaining": 1,
    "can_generate": true
  },
  "resets_at": "2025-12-01T00:00:00+00:00"
}

Response (Free Plan)

200 OK
{
  "message": "LLMS.txt generation is only available for Pro and Max plans.",
  "has_access": false
}
Usage Tracking: The generation limit resets at the beginning of each month. Use this endpoint to check remaining quota before attempting to generate.

Complete Workflow Example

1. Check Usage & Access

curl https://app.geoleaper.com/api/llms-txt/usage \
  -H "Authorization: Bearer YOUR_API_TOKEN"

2. Create Generation

curl -X POST https://app.geoleaper.com/api/llms-txt \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

# Response:
{
  "id": 1,
  "check_url": "https://app.geoleaper.com/api/llms-txt/1"
}

3. Poll for Completion

Poll every 30 seconds until status is completed:

curl https://app.geoleaper.com/api/llms-txt/1 \
  -H "Authorization: Bearer YOUR_API_TOKEN"

4. Download or Use Content

Option A: Download as file

curl https://app.geoleaper.com/api/llms-txt/1/download \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -o llms.txt

Option B: Get content in JSON

curl https://app.geoleaper.com/api/llms-txt/1 \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Use the "content" field from the response
Important Notes:
  • Generation takes 2-5 minutes on average
  • The AI analyzes up to 5 pages from your website
  • Content is always generated in English, regardless of source language
  • Rate limit: 3 generations per month for all Pro/Max plans
  • Limit resets on the 1st of each month

Tenant Endpoints

GET
/tenant

Get current tenant information including package, features, limits, and usage.

Response

200 OK
{
  "id": 1,
  "name": "My Company",
  "package": "pro",
  "package_description": "Analyze with AI up to 200 different URLs on 1 domain",
  "features": {
    "perfect_json_ld": true,
    "llms_txt_generation": true,
    "ollama_detection": true,
    "custom_prompts": true
  },
  "limits": {
    "max_urls": 200,
    "max_domains": 1,
    "analyses_per_month": 200,
    "bulk_limit": 200,
    "llms_txt_per_month": 3
  },
  "usage": {
    "analyses_this_month": 45,
    "unique_urls_analyzed": 87,
    "unique_domains_analyzed": 1,
    "urls_remaining": 113,
    "domains_remaining": 0,
    "llms_txt_generated_this_month": 2,
    "llms_txt_remaining": 1
  },
  "created_at": "2025-01-01T00:00:00+00:00"
}
PUT
/tenant

Update tenant settings.

Request Body

{
  "name": "Updated Company Name"
}

Response

200 OK
{
  "message": "Tenant updated successfully",
  "tenant": {
    "id": 1,
    "name": "Updated Company Name",
    "package": "pro"
  }
}
GET
/tenant/usage

Get tenant's current usage and quota information including package details, URLs analyzed, and remaining limits.

Response

200 OK
{
  "package": "pro",
  "urls_analyzed": 5,
  "urls_remaining": 995,
  "urls_limit": 1000,
  "domains_analyzed": 2,
  "domains_remaining": 3,
  "domains_limit": 5,
  "llms_txt_generated": 2,
  "llms_txt_remaining": 1,
  "llms_txt_limit": 3
}

Response Fields

Field
Type
Description
package string Current package: "free", "pro", or "max"
urls_analyzed integer Total unique URLs analyzed this month
urls_remaining integer Remaining URL quota for this month
urls_limit integer Total URL limit per month
domains_analyzed integer Total unique domains analyzed
domains_remaining integer Remaining domain quota
domains_limit integer Total domain limit
llms_txt_generated integer LLMS.txt files generated this month
llms_txt_remaining integer Remaining LLMS.txt generations this month
llms_txt_limit integer Total LLMS.txt generation limit per month (3 for Pro/Max)
Usage Tracking: Use this endpoint to display quota information in your application, warn users when approaching limits, or determine if they need to upgrade their plan. LLMS.txt generation is limited to 3 per month for Pro and Max plans.
GET
/tenant/stats

Get detailed statistics for the tenant including analysis counts, average scores, and top performers.

Response

200 OK
{
  "total_analyses": 150,
  "completed_analyses": 145,
  "failed_analyses": 3,
  "pending_analyses": 2,
  "average_score": 82.5,
  "this_month": {
    "total": 45,
    "completed": 43,
    "average_score": 85.2
  },
  "top_scores": [
    {
      "id": 10,
      "url": "https://example.com/best-page",
      "total_score": 98,
      "created_at": "2025-11-01T10:00:00+00:00"
    }
  ]
}
GET
/tenant/dashboard

Get dashboard statistics with optional filters for domain and date range. Returns stats cards, recent analyses, and available domains.

Query Parameters

Parameter
Type
Required
Description
domain string No Filter by specific domain
from_date date No Start date (YYYY-MM-DD)
to_date date No End date (YYYY-MM-DD)

Example Request

curl "https://app.geoleaper.com/api/tenant/dashboard?domain=example.com&from_date=2025-11-01&to_date=2025-11-30" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Response

200 OK
{
  "stats": {
    "total_analyses": 13,
    "average_score": 63,
    "analyses_this_week": 13,
    "critical_issues": 0
  },
  "recent_analyses": [
    {
      "id": 13,
      "url": "https://example.com",
      "total_score": 63,
      "grade": "D",
      "status": "completed",
      "created_at": "2025-11-20T11:43:02+00:00"
    },
    {
      "id": 12,
      "url": "https://example.com/page",
      "total_score": 85,
      "grade": "B",
      "status": "completed",
      "created_at": "2025-11-20T11:42:39+00:00"
    }
  ],
  "available_domains": [
    "example.com",
    "another-site.com"
  ]
}
Usage: This endpoint mirrors the dashboard view, providing filtered statistics and recent analyses. Use available_domains to populate filter dropdowns in your UI.
GET
/tenant/score-distribution

Get score distribution by grade (A-F) with optional filters for domain and date range. All grades are always included in the response with a count of 0 if no analyses match that grade.

Query Parameters

Parameter
Type
Required
Description
domain string No Filter by specific domain
from_date date No Start date (YYYY-MM-DD)
to_date date No End date (YYYY-MM-DD)

Example Request

curl "https://app.geoleaper.com/api/tenant/score-distribution?domain=example.com" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Response

200 OK
{
  "distribution": {
    "A": 5,
    "B": 12,
    "C": 8,
    "D": 3,
    "F": 2
  },
  "total": 30
}

Grade Calculation

Grade
Score Range
Description
A
90-100 Excellent AI visibility
B
80-89 Good AI visibility
C
70-79 Fair AI visibility
D
60-69 Poor AI visibility
F
0-59 Very poor AI visibility

User Endpoints

GET
/user

Get current user information.

Response

200 OK
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "tenant_id": 1,
  "created_at": "2025-01-01T00:00:00+00:00"
}
PUT
/user

Update user profile.

Request Body

{
  "name": "Jane Doe",
  "email": "jane@example.com"
}
GET
/user/stats

Get detailed user statistics.

Response

200 OK
{
  "total_analyses": 75,
  "completed_analyses": 72,
  "failed_analyses": 2,
  "pending_analyses": 1,
  "average_score": 84.3,
  "best_score": 98,
  "worst_score": 45,
  "this_week": {
    "total": 15,
    "completed": 14
  },
  "this_month": {
    "total": 45,
    "completed": 43
  },
  "recent_analyses": [
    {
      "id": 123,
      "url": "https://example.com/page",
      "status": "completed",
      "total_score": 92,
      "created_at": "2025-11-20T10:00:00+00:00"
    }
  ]
}

Reference

HTTP Status Codes

Code
Description
When
200
Success Request succeeded
202
Accepted Processing in background
401
Unauthorized Missing or invalid authentication
404
Not Found Resource doesn't exist
422
Validation Error Invalid request data
500
Server Error Analysis failed or server error

Analysis Statuses

Status
Description
Next Action
pending Queued, not started yet Wait and poll
analyzing Fetching HTML and analyzing Wait and poll
generating Generating perfect JSON-LD (Pro/Max) Wait and poll
completed Analysis complete Read results
failed Analysis failed Check error field

Score Breakdown

Total score: 0-100 points (4 categories × 25 points each)

Schema Coverage (0-25)

Policy Compliance: Single primary Organization, logo with dimensions, URL consistency. Based on criteria-based scoring system.

Schema Integrity (0-25)

Data Completeness: Required fields for page type (WebSite, Organization, logo, SearchAction). Based on criteria-based scoring system.

Entity Clarity (0-25)

Entity Disambiguation: BreadcrumbList, sameAs links, @id consistency. Based on criteria-based scoring system.

AI Readability (0-25)

Source Credibility: ContactPoint, Organization ownership, policy references. Based on criteria-based scoring system.

Note: Scores are calculated based on implemented checks only. Unimplemented checks are excluded from scoring to ensure fair evaluation. The criteria_details field in API responses provides full breakdown of checks and evidence.

Package Comparison

Free

$0

per month

Analyze basic without AI up to 10 different URLs on 1 domain

10 unique URLs
1 domain
WordPress Plugin
Sitemap Analysis
LLMS.txt Generation
AI-powered analysis
API Access
Priority Support

Pro

$29

per month

Analyze with AI up to 200 different URLs on 1 domain

200 unique URLs
1 domain
WordPress Plugin
Sitemap Analysis
LLMS.txt Generation (3/month)
AI-powered analysis
API Access
Priority Support

Max

$129

per month

Analyze with AI up to 1500 different URLs on 5 domains

1500 unique URLs
5 domains
WordPress Plugin
Sitemap Analysis
LLMS.txt Generation (3/month)
AI-powered analysis
API Access
Priority Support

Geoleaper API

Template-based AI visibility scoring system. Analyze and optimize your web pages for AI search engines.

Quick Links

Support

For support, please contact:
support@geoleaper.com

Geoleaper API v2.2 • © 2025 Aivaton AB • All rights reserved