Specoria API, MCP and GitHub Action
Run the free agent-readiness test from your own scripts, CI or AI assistant, and read your project’s tasks over MCP. Same rules as the test on this site; the API never calls an AI model.
What the API does
- POST https://app.specoria.com/v1/scan runs the same free test as specoria.com on one website and returns the result as JSON: score 0-100, level, critical blockers and every check with its status and weight.
- The scan reads public pages on the given domain only, over https, and never follows a redirect to another domain. Marketplace pages and excluded domains are refused.
- The request is synchronous. Page reading has a 20-second budget, so allow a client timeout of at least 60 seconds.
- If the same domain was scanned in the last 6 hours, the stored result is returned without visiting the site again ("cached": true).
- The API is versioned under /v1. New fields may be added to a response; existing fields won’t change meaning within v1.
API keys
- Create a key in the Specoria panel: Team and profile → API keys. Project admins and commercial approvers can create and revoke keys; up to 10 active keys per organization.
- The key is shown once. We store only its SHA-256 hash and the first 12 characters for display.
- Send it as a header: Authorization: Bearer spk_…, never in a URL. The API doesn’t allow browser (CORS) calls, so keep the key on a server or in CI secrets.
- A key belongs to your organization and only sees your organization’s projects. It stops working when it is revoked or when the person who created it leaves the team.
Limits
- Per key: 60 scans per hour and 500 scans per day; MCP read tools: 300 requests per hour.
- All keys of one organization together: 60 scans per hour and 500 scans per day (more keys don’t raise the limit).
- Cached results count towards the limit; invalid requests (bad URL, marketplace, excluded domain) don’t.
- Over the limit you get HTTP 429 with a Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining for the hourly window.
- The API has its own share of the service’s daily scan capacity: 100 new scans per day across all API users (cached results don’t count), so it never uses up the free test on our site. When the share or the overall capacity is used up you get HTTP 503 "busy".
Request
| Field | Type | Meaning |
|---|---|---|
url | string, required | Site address, e.g. https://example.com (max 300 characters, no port or credentials). |
lang | "en" | "tr", optional | Language of check titles and help links; also the Accept-Language for generic domains. Default en. |
share | boolean, optional | Also create a shareable result link, kept for 30 days, with a link to remove it early. Default false. |
Example
curl -sS --max-time 90 -X POST https://app.specoria.com/v1/scan \
-H "Authorization: Bearer $SPECORIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","lang":"en"}'
Response
On success: {"success": true, "data": {…}}. The fields of data:
| Field | Meaning |
|---|---|
api_version, model_version | API version (v1) and scoring model version of this result. |
domain, scanned_at, cached | Domain measured, when, and whether the result came from the 6-hour cache. |
score | Score 0-100 after critical-blocker caps; null when too little could be measured (insufficient: true). |
raw_score, potential | Weighted score before caps; the score reachable by fixing the top three priorities. |
level | ready, partial or low. |
site_type | ecommerce, lodging or service: which set of checks applied. |
blockers, priorities | Ids of failed critical checks; fix order. |
categories, coverage | Score per category; how many checks were measured, couldn’t be verified or didn’t apply. |
checks[] | id, title, status (pass, warn, fail, na), weight, critical, blocker, reason (why not measured), help_url. |
method_url, share | How the score is computed; the share link (url, revoke_url, expires_at) or null. |
{
"success": true,
"data": {
"api_version": "v1",
"model_version": "v2.4",
"domain": "specoria.com",
"scanned_at": "2026-10-08T14:02:48.579Z",
"cached": false,
"score": 75,
"level": "partial",
"insufficient": false,
"blockers": [],
"checks": [
{
"id": "bots_search",
"status": "pass",
"weight": 8,
"…": "…"
},
{
"id": "waf_access",
"status": "pass",
"weight": 8,
"…": "…"
},
{
"id": "no_js",
"status": "na",
"weight": 5,
"…": "…"
}
],
"…": "…"
}
}
Abbreviated example built from our own free-test result for specoria.com, scanned 2026-10-08 (full JSON on the method page). How the free test works
Errors
{"success": false, "error": "…", "message": "…"}
| HTTP | error | When |
|---|---|---|
| 400 | invalid_json, invalid_body, invalid_url | Body isn’t JSON, a field has the wrong type, or the URL isn’t a public website address. |
| 401 | missing_api_key, invalid_api_key | No Bearer key, or the key is unknown, revoked or its creator left the team. |
| 413 | too_large | Body larger than 8 KB. |
| 422 | marketplace, blocked_domain, unreachable, redirect | Marketplace page; excluded domain; home page didn’t open; home page redirects to another domain. |
| 429 | rate_limited | Limit reached; see Retry-After. |
| 502 / 503 | scan_failed / busy | Unexpected failure; daily capacity used up. Try again later. |
MCP server for your projects
POST https://app.specoria.com/v1/mcp speaks MCP over Streamable HTTP (stateless, JSON responses) with the same key and limits. Tools:
| Tool | What it does |
|---|---|
scan_store | The same scan as /v1/scan; counts towards the scan limit. |
list_projects | Your organization’s projects: domain, latest score, critical blockers, open and done tasks. |
get_project_tasks | Tasks shown in your panel for one project (by project_id or domain); status open, todo, ongoing, done or all. |
Client configuration (for clients that accept a URL and headers)
{
"mcpServers": {
"specoria": {
"type": "http",
"url": "https://app.specoria.com/v1/mcp",
"headers": {
"Authorization": "Bearer ${SPECORIA_API_KEY}"
}
}
}
}
GitHub Action
A small action (action.yml plus one JavaScript file, Node.js built-ins only) calls /v1/scan, writes a summary table to the job and fails the step when the score is below min-score.
- uses: <owner>/<repo>/integrations/github-action@<ref>
with:
url: https://example.com
api-key: ${{ secrets.SPECORIA_API_KEY }}
min-score: 70
- Inputs: url, api-key, min-score (default 0), fail-on-blockers, lang, share. Outputs: score, level, blockers, passed, share-url.
- A missing score (too little measured) fails the step, because there is nothing to compare.
- It isn’t listed on the GitHub Marketplace yet. Write to contact@specoria.com and we’ll send you the action files to put in your repository.
What the API doesn’t do
- No deep audit, agent simulation, AI visibility or ChatGPT Shopping measurement: those stay in the panel and plans.
- No AI model is called during an API scan.
- No writes: it never changes your store or your project, and there are no webhooks.
- No browser calls (CORS) and no keys in URLs.
Questions
Do I need a paid plan?
No. Any project admin or commercial approver can create a key in the panel. The limits above apply to every key.
Is the API result the same as the test on specoria.com?
Same scan, same scoring model and the same cache. One difference: when switched on, the test on the site may use a small AI model to fill in policy details the rules couldn’t read (for example a return period). The API never calls an AI model, so a fresh API result can occasionally differ slightly; a cached result may come from a site test that used it.
Can I scan sites I don’t own?
The scan reads only public pages, like the free test on this site. Owners can ask for their domain to be excluded (see our crawler page).