Overview

Seonar is a technical SEO analysis API. Send a URL — get back a structured JSON audit covering up to 9 checks: robots.txt, sitemap, meta tags, canonical tags, structured data, security headers, redirect chains, hreflang, and internal links.

The API is HTTP-based, uses Bearer token authentication, and always returns the same predictable JSON shape — easy to parse in any language or pipeline.

9
Technical checks
1
Endpoint to learn
JSON
Always structured

Base URL

https://seonar.io/api/v1

Authentication

All check requests require a Bearer token in the Authorization header. Obtain your token from the Dashboard after registering.

Every authenticated request
Authorization: Bearer sk_live_••••••••••••••••••••••

Keep your token secret. Never expose it in client-side code or public repositories.

Creating a token

Go to the Dashboard, enter a name for the token, and click Create token. The token is shown once — copy it immediately.

You can create multiple tokens (e.g., one per project) and revoke them individually.

Quick Start

Run your first full audit in under a minute:

1

Register for a free account and generate an API token in the Dashboard.

2

Run the request below — replace {token} and the URL.

3

Parse the JSON response — check summary.overall_score or iterate over results.

cURL — full audit
curl -X POST https://seonar.io/api/v1/check \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-site.com"}'
Response (abbreviated)
{
  "url": "https://your-site.com",
  "checked_at": "2026-02-25T10:00:00+00:00",
  "results": {
    "robots_txt":      { "status": "pass", "score": 100 },
    "sitemap":         { "status": "pass", "score": 100 },
    "meta_tags":       { "status": "warn", "score": 70  },
    "internal_links":  { "status": "fail", "score": 40  }
    // ... 5 more checks
  },
  "summary": {
    "total_checks": 9, "passed": 6, "warnings": 2,
    "failed": 1, "errors": 0, "overall_score": 82
  }
}

POST /api/v1/check

Run a technical SEO audit on a URL. Requires authentication.

Request

Field Type Required Description
url string Yes The URL to audit. Must start with http:// or https://.
checks string[] No Array of check keys to run. Omit to run all 9 checks. See Checks Reference for valid values.
Run specific checks only
POST /api/v1/check
Authorization: Bearer {token}
Content-Type: application/json

{
  "url":    "https://example.com",
  "checks": ["robots_txt", "sitemap", "meta_tags"]
}

Response

Returns 200 OK with a JSON body. See Response Format for the full structure.

GET /api/v1/checks

Returns the list of all available check keys and their descriptions. No authentication required.

List available checks
GET /api/v1/checks
Response
{
  "checks": [
    { "key": "robots_txt",       "name": "robots.txt"         },
    { "key": "sitemap",           "name": "Sitemap"             },
    { "key": "meta_tags",         "name": "Meta Tags"           },
    { "key": "canonical",         "name": "Canonical"           },
    { "key": "structured_data",   "name": "Structured Data"     },
    { "key": "security_headers",  "name": "Security Headers"    },
    { "key": "redirect_chain",    "name": "Redirect Chain"      },
    { "key": "hreflang",          "name": "Hreflang"            },
    { "key": "internal_links",    "name": "Internal Links"      }
  ]
}

Response Format

Every POST /check response follows this structure:

{
  "url":        "https://example.com",        // audited URL
  "checked_at": "2026-02-25T10:00:00+00:00", // ISO 8601
  "results":    { /* keyed by check name */ },
  "summary":    { /* aggregate stats */ }
}

Check result object

Each key in results contains:

FieldTypeDescription
status string pass warn fail error
score integer 0–100. Higher is better. pass always returns 100.
issues Issue[] Array of detected issues. Empty array when status is pass.
data object Raw extracted data specific to each check. Schema varies — see each check's reference below.

Issue object

FieldTypeDescription
severity string critical warning info
message string Short human-readable description of the issue.
detail string|null Actionable explanation or recommendation. May be null.

Summary object

FieldTypeDescription
total_checksintegerNumber of checks that were run.
passedintegerChecks with status pass.
warningsintegerChecks with status warn.
failedintegerChecks with status fail.
errorsintegerChecks that could not be completed (connectivity issues, etc.).
overall_scoreintegerAverage score across all executed checks (0–100).

Rate Limits

Rate limits are enforced per API token.

ContextLimit
POST /api/v1/check 20 requests / minute per token
GET /api/v1/checks 3 requests / minute per IP (no auth required)

When a rate limit is exceeded, the API returns 429 Too Many Requests. The response includes standard Laravel throttle headers:

X-RateLimit-Limit:     20
X-RateLimit-Remaining: 0
Retry-After:          42   # seconds until limit resets

Errors

The API uses standard HTTP status codes. Error responses always include a JSON body.

HTTP StatusMeaning
400 Validation error — missing or invalid url field.
401 Missing or invalid Bearer token.
422 Unprocessable — request body is valid JSON but fails business validation.
429 Rate limit exceeded. See Rate Limits.
500 Server error. Contact hello@seonar.io if it persists.
Validation error (400/422)
{
  "message": "The url field is required.",
  "errors": {
    "url": ["The url field is required."]
  }
}

A check-level status: "error" in a result object means that specific check could not be completed (e.g., timeout connecting to the target site). The HTTP response is still 200 OK — the error is scoped to that individual check.

Checks Reference

Detailed documentation for each check — what it tests, all data fields, and scoring logic.

robots_txt

Fetches /robots.txt from the target host and checks for correctness, crawler restrictions, and a Sitemap directive.

data fields

FieldTypeDescription
existsbooleanWhether robots.txt was found (HTTP 200).
urlstringThe full URL that was checked.
size_bytesintegerFile size in bytes.
disallowsstring[]All Disallow: directives found.
allowsstring[]All Allow: directives found.
sitemapsstring[]Sitemap URLs declared via Sitemap: directive.
blocks_allbooleantrue if Disallow: / is present for any User-agent.

Scoring

  • 100 File exists, no block-all, has Sitemap directive.
  • 70 File exists but missing Sitemap directive.
  • 10 Disallow: / found — entire site blocked.
  • 0 File not found (HTTP 404).

sitemap

Discovers the sitemap URL from robots.txt or falls back to /sitemap.xml, then validates its XML structure and content.

data fields

FieldTypeDescription
existsbooleanWhether a sitemap was found.
urlstringThe sitemap URL that was fetched.
formatstringurlset or sitemap_index.
url_countintegerNumber of URLs (or child sitemaps for sitemap_index).
has_lastmodbooleanWhether at least one <lastmod> date is present.
has_imagesbooleanWhether image sitemap extensions (image: namespace) are used.

Scoring

  • 100 Sitemap found, valid XML, contains URLs.
  • 60 Sitemap has more than 50,000 URLs (limit exceeded).
  • 40 Sitemap contains no URLs.
  • 0 Sitemap not found.

meta_tags

Fetches the page HTML and validates title length, meta description, Open Graph tags, and Twitter Card.

data fields

FieldTypeDescription
title.valuestring|nullThe raw <title> text.
title.lengthintegerCharacter count of the title.
meta_description.valuestring|nullThe meta description content.
meta_description.lengthintegerCharacter count of the description.
og.titlestring|nullog:title content.
og.descriptionstring|nullog:description content.
og.imagestring|nullog:image URL.
twitter_cardstring|nulltwitter:card value (e.g. summary_large_image).

Scoring

  • 100 All tags present and within recommended lengths.
  • 70–90 Missing OG tags or title/description length outside 30–60 / 50–160 char range.
  • ≤55 Missing <title> (−30) or meta description (−25).

canonical

Checks for the presence of a <link rel="canonical"> tag, verifies it is self-referencing, and detects conflicting multiple canonicals.

data fields

FieldTypeDescription
is_presentbooleanWhether a canonical tag exists.
canonical_urlstring|nullThe href value of the canonical tag.
is_self_canonicalbooleanWhether the canonical points back to the same URL.
all_canonicalsstring[]All canonical href values found (multiple = problem).

Scoring

  • 100 Present and self-referencing.
  • 70 Present but points to a different URL.
  • 60 Canonical tag missing.
  • 20 Multiple conflicting canonical tags.

structured_data

Finds all <script type="application/ld+json"> blocks, validates their JSON syntax, extracts schema types, and flags rich-snippet-eligible types.

data fields

FieldTypeDescription
countintegerTotal number of schema items found (including @graph items).
schemas[].typestringThe @type value (e.g. Article, Product).
schemas[].validbooleanWhether the JSON block was parseable.
schemas[].is_rich_eligiblebooleanWhether the type qualifies for Google rich snippets.

Rich-eligible types

Article, BlogPosting, Product, Review, Recipe, Event, FAQPage, HowTo, Person, Organization, WebSite, BreadcrumbList, LocalBusiness, JobPosting, Course, VideoObject

security_headers

Issues a HEAD request and checks five security-related response headers, plus HTTPS enforcement. Relevant for SEO because Google gives a slight ranking signal to secure sites and headers affect trust signals.

data fields

FieldTypeDescription
httpsbooleanWhether the URL uses HTTPS.
hstsbooleanStrict-Transport-Security header present.
x_frame_optionsbooleanX-Frame-Options header present.
x_content_type_optionsbooleanX-Content-Type-Options header present.
content_security_policybooleanContent-Security-Policy header present.
referrer_policybooleanReferrer-Policy header present.

Scoring

  • 100 All headers present, HTTPS enforced.
  • 80 Missing HSTS or X-Frame-Options (−10 each).
  • ≤70 Site not on HTTPS (−30).

CSP, X-Content-Type-Options, and Referrer-Policy are info level — they reduce score indirectly only if combined with other issues.

redirect_chain

Follows redirects one hop at a time (max 10), recording each step. Detects loops, oversized chains, and non-HTTPS final destinations.

data fields

FieldTypeDescription
chainarrayEach step: {"url": "...", "status": 301}.
chain_lengthintegerTotal number of hops (including the final destination).
final_urlstringThe URL at the end of the chain.
final_statusintegerHTTP status of the final destination.
is_httpsbooleanWhether the final URL is HTTPS.

Scoring

  • 100 No redirects, or a single clean HTTP→HTTPS redirect.
  • 70 3 hops.
  • 20 More than 3 hops.
  • 0 Redirect loop detected.

hreflang

Detects <link rel="alternate" hreflang="…"> tags, validates language codes against BCP 47, checks for duplicates, and verifies x-default presence.

If no hreflang tags are found, the check returns pass with an informational note — single-language sites don't need hreflang.

data fields

FieldTypeDescription
has_hreflangbooleanWhether any hreflang tags were found.
countintegerNumber of language alternates (excluding x-default).
languagesarrayEach entry: {"lang": "en-US", "href": "https://..."}.
has_x_defaultbooleanWhether hreflang="x-default" is present.

Ready to integrate? Get your free API key in 30 seconds.

Create free account