Frase Audits API

Site audits and SEO analysis

GitHub OpenAPI

Operations 5

GET /audits List audits #
POST /audits Start audit #
GET /audits/{id} Get audit #
GET /audits/{id}/export Export audit #
POST /audits/page Audit a single page #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/frase-io:frase-io-audits-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

frase-io-audits-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Frase Audits API
  version: 1.0.0
  description: 'The Frase API provides programmatic access to your SEO content platform. Use it to manage content, research, audits, AI visibility tracking, and more. ## Authentication


    All API requests require authentication using an API key. Include your key in the `X-API-KEY` header:


    ```

    X-API-KEY: sk_live_your_api_key_here

    ```


    For legacy compatibility, the `token` header is also supported. ## Rate Limits


    Three independent limits apply, each with its own headers and error code. Headers are returned on `429` responses, not on successful ones. **Per-minute burst** - 60/min on trial and Starter, 120 Professional, 300 Scale, 1,000 Enterprise. Error code `rate_limit_exceeded`. - `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (epoch seconds)


    **Sustained hourly ceiling** - 2,000/hour trial, 3,000 Starter, 5,000 Professional, 15,000 Scale, 50,000 Enterprise. Error code `hourly_limit_exceeded`. - `X-RateLimit-Hourly-Limit`, `X-RateLimit-Hourly-Remaining`, `X-RateLimit-Hourly-Reset` (epoch seconds)


    **Monthly request budget** - error code `monthly_budget_exceeded`, headers `X-Monthly-Limit`, `X-Monthly-Used`, `X-Monthly-Remaining`. Every `429` carries `Retry-After` in seconds. On the hourly ceiling this can be up to 3,600, so clients should honour it rather than retrying on a short fixed backoff - a retry sooner than `Retry-After` cannot succeed. ## Errors


    The API uses standard HTTP status codes and returns errors in a consistent format:


    ```json

    {

    "error": {

    "type": "authentication_error",

    "code": "invalid_api_key",

    "message": "Invalid API key provided.",

    "doc_url": "https://docs.frase.io/api/errors#invalid_api_key"

    }

    }

    ```


    ## Changelog


    Breaking changes are listed here, newest first. "Breaking" means a field that was always present with a value can now be `null`, or an existing value now means something different — not that a field was removed or renamed. Additive fields are not listed. ### 2026-08-31 — Fact `sources[]` may omit `url`, and minted facts default to `approved`


    - `GET /briefs/{id}/facts`, `PATCH /briefs/{id}/facts/{factId}` → a `sources[]` entry may now carry only `title`, with no `url` or `domain`. Research names a publisher far more often than it captures a link (793 of 801 plan-evidence items in production), and those names were previously discarded rather than returned. Read `url` defensively. - `GET /briefs/{id}/facts` → `approval` on a newly minted fact is now `approved` rather than `pending`. A client polling for `pending` facts to review will see far fewer; rejection is unchanged and remains permanent. Facts the writer asserted in its own output (`provenance: generated`) are still minted `pending`. ### 2026-08-24 — Content Guard''s hasPublishedUrl is now recoverability, not the stored URL


    - `GET /content/{id}/monitoring` → `hasPublishedUrl`: was a judgment on the STORED URL (false for a relative path even when the page was live). It now answers "could Guard watch this article right now" — the stored URL when absolute, or an address the server recovers (CMS inventory; FraseCMS re-derivation from current settings when a live published post exists). `true` no longer implies the stored URL itself is absolute, and a FraseCMS article published before domain setup flips to `true` when setup finishes, with no re-publish. It remains exactly the condition enabling enforces. - `publishedUrlIssue` is now the RESIDUAL after recovery failed, not a raw-column classification — "not_absolute" can also mean the FraseCMS post is not live or FraseCMS is disabled for the site. - `POST /content/{id}/publish` → `url` (frase_cms): now derived from the site''s current CMS settings rather than the adapter''s host-of-the-moment value; the same URL is stored on the content row and sent in the content.published webhook.'
  contact:
    name: Frase Support
    url: https://frase.io
    email: support@frase.io
  license:
    name: Proprietary
    url: https://www.frase.io/company/terms
servers:
- url: https://next.frase.io/api/v1
  description: Production
- url: /api/v1
  description: This host
security:
- ApiKeyAuth: []
- BearerAuth: []
tags:
- name: Audits
  description: Site audits and SEO analysis
paths:
  /audits:
    get:
      operationId: listAudits
      summary: List audits
      description: Retrieve all site audits.
      tags:
      - Audits
      parameters:
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: page_size
        in: query
        schema:
          type: integer
          default: 20
      - name: site_id
        in: query
        schema:
          type: string
          format: uuid
      - name: status
        in: query
        schema:
          type: string
          enum:
          - pending
          - crawling
          - analyzing
          - completed
          - failed
      responses:
        '200':
          description: List of audits
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                          nullable: true
                        type:
                          type: string
                        status:
                          type: string
                        progress:
                          type: integer
                          nullable: true
                        pages_audited:
                          type: integer
                        total_issues:
                          type: integer
                        critical_issues:
                          type: integer
                        overall_score:
                          type: integer
                          nullable: true
                        site:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            domain:
                              type: string
                        created_at:
                          type: string
                          format: date-time
                        completed_at:
                          type: string
                          format: date-time
                          nullable: true
                  request_id:
                    type: string
                  pagination:
                    $ref: '#/components/schemas/Pagination'
    post:
      operationId: startAudit
      summary: Start audit
      description: Start a new site audit.
      tags:
      - Audits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - site_id
              properties:
                site_id:
                  type: string
                  format: uuid
                name:
                  type: string
                  description: Custom audit name
                type:
                  type: string
                  enum:
                  - full
                  - quick
                  - technical
                max_pages:
                  type: integer
                  description: Maximum pages to crawl
                selected_page_urls:
                  type: array
                  items:
                    type: string
                  description: Specific URLs to audit
                settings:
                  type: object
                  description: Advanced audit settings
      responses:
        '201':
          description: Audit started
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                        nullable: true
                      type:
                        type: string
                      status:
                        type: string
                      site:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          domain:
                            type: string
                      created_at:
                        type: string
                        format: date-time
                  request_id:
                    type: string
  /audits/{id}:
    get:
      operationId: getAudit
      summary: Get audit
      description: Retrieve audit details and summary.
      tags:
      - Audits
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: include_pages
        in: query
        schema:
          type: boolean
          default: false
        description: Include audited pages in response
      - name: page_limit
        in: query
        schema:
          type: integer
          default: 50
        description: Max pages to include (when include_pages=true)
      responses:
        '200':
          description: Audit details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      name:
                        type: string
                        nullable: true
                      type:
                        type: string
                      status:
                        type: string
                      progress:
                        type: integer
                        nullable: true
                      pages_audited:
                        type: integer
                        nullable: true
                      total_issues:
                        type: integer
                        nullable: true
                      critical_issues:
                        type: integer
                        nullable: true
                      overall_score:
                        type: integer
                        nullable: true
                      summary:
                        type: object
                        nullable: true
                      cannibalization:
                        type: array
                        nullable: true
                        description: Keyword-cannibalization groups from this audit. Null until the cannibalization pass has run. Each group carries the keyword and the competing pages; see GET /site-health/cannibalization for the same data with a stable per-group shape.
                        items:
                          type: object
                      internal_link_graph:
                        type: object
                        nullable: true
                        description: The crawl's internal link graph as stored by the audit pipeline. Null until the link-graph pass has run. Per-page link facts are on pages[] (internal_page_rank, internal_links_in/out, click_depth, is_orphan, is_dead_end); this object is the raw graph behind them.
                        properties: {}
                      site:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                            nullable: true
                          domain:
                            type: string
                      created_at:
                        type: string
                        format: date-time
                      completed_at:
                        type: string
                        format: date-time
                        nullable: true
                      pages:
                        type: array
                        nullable: true
                        description: Included when include_pages=true
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                            url:
                              type: string
                            title:
                              type: string
                              nullable: true
                            status_code:
                              type: integer
                              nullable: true
                              description: 'Final HTTP status of the fetch, after redirects. Recorded on crawler-discovered pages AND on manually scoped (selected-URL) audits; null only where no status was captured, which is not evidence the page was reachable. A row with status_code >= 400 is a dead-page tombstone rather than a page: it is excluded, carries no score and no issues, and exists only so the site view can retire the URL. Dead URLs that other pages still link to also surface as broken_link issues on the linking page; unlinked ones surface in the app as a single site-wide dead_page finding, which no v1 endpoint emits today.'
                            score:
                              type: integer
                              nullable: true
                              description: 'Canonical page-v2 score: the equal mean of E-E-A-T, SEO and GEO. The same formula is used by crawl, API and synchronous single-page audits. Null when any required pillar is unmeasured — never replaced by a different formula. Formula version and coverage are recorded in analysis_provenance.score.'
                            issues:
                              type: array
                              items:
                                type: object
                            word_count:
                              type: integer
                              nullable: true
                            aeo_score:
                              type: integer
                              nullable: true
                              description: Answer-engine optimization score, 0-100.
                            technical_score:
                              type: integer
                              nullable: true
                              minimum: 0
                              maximum: 100
                              description: 'Derived from indexability directives, canonical, head metadata, social/viewport tags, structured data, image alt text and broken internal links. Uses the authoritative stored projection when present; for historical rows where that projection is absent, derives the same score at read time from evidence already stored on the row without modifying it. This endpoint and GET /site-health therefore report the same number for the same page. Null when no technical check could run at all — the fetch was unreliable, or no head was parsed and no head-independent check found anything — which is not the same as 0. A page whose head was never parsed is scored on the checks that never needed one (title, meta description, H1 structure, image alt text, broken links) rather than dropped. Does not include page speed or internal-link authority — see internal_page_rank for the latter. Additive: this field is new in this response, so no existing consumer loses a value. Guard for null before arithmetic.'
                            internal_page_rank:
                              type: integer
                              nullable: true
                              minimum: 0
                              maximum: 100
                              description: PageRank over the site's internal link graph, min-max normalized across the crawled set, so it is not comparable between runs of different sizes.
                            internal_links_in:
                              type: integer
                              nullable: true
                            internal_links_out:
                              type: integer
                              nullable: true
                            click_depth:
                              type: integer
                              nullable: true
                              description: Clicks from the site root. null = not measured (the crawl contained no site root). -1 = measured and unreachable. >= 0 = depth.
                            is_orphan:
                              type: boolean
                              nullable: true
                              description: null = the link graph was not measured; false genuinely means the page is not an orphan.
                            is_dead_end:
                              type: boolean
                              nullable: true
                              description: null = the link graph was not measured; false genuinely means the page is not a dead end.
                            eeat_score:
                              type: integer
                              nullable: true
                            geo_score:
                              type: integer
                              nullable: true
                            seo_score:
                              type: integer
                              nullable: true
                            agent_readiness_score:
                              type: integer
                              nullable: true
                              description: Null on pages audited before agent-readiness probing existed.
                            agent_readiness_breakdown:
                              type: object
                              nullable: true
                            scoring_version:
                              type: string
                              nullable: true
                  request_id:
                    type: string
  /audits/{id}/export:
    get:
      operationId: exportAudit
      summary: Export audit
      description: Export audit report in JSON or CSV format.
      tags:
      - Audits
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: format
        in: query
        schema:
          type: string
          enum:
          - json
          - csv
          default: json
      responses:
        '200':
          description: Exported audit
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      site_id:
                        type: string
                        nullable: true
                      site_domain:
                        type: string
                        nullable: true
                      type:
                        type: string
                      status:
                        type: string
                      summary:
                        type: object
                        properties:
                          total_pages:
                            type: integer
                          crawled_pages:
                            type: integer
                          avg_word_count:
                            type: number
                          total_issues:
                            type: integer
                          critical_issues:
                            type: integer
                          warning_issues:
                            type: integer
                      pages:
                        type: array
                        items:
                          type: object
                      created_at:
                        type: string
                        format: date-time
                      completed_at:
                        type: string
                        format: date-time
                        nullable: true
                      export_format:
                        type: string
                      exported_at:
                        type: string
                        format: date-time
                  request_id:
                    type: string
            text/csv:
              schema:
                type: string
  /audits/page:
    post:
      operationId: auditPage
      summary: Audit a single page
      description: Synchronously scrape and audit a single URL, returning E-E-A-T, GEO, and SEO scores along with detected issues. Every route uses the canonical page scorer; no background audit job is queued.
      tags:
      - Audits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - url
              properties:
                url:
                  type: string
                  format: uri
                  description: The URL to audit. Must be http or https.
                keyword:
                  type: string
                  description: Optional target keyword for SEO scoring context.
                audit_page_id:
                  type: string
                  format: uuid
                  description: Optional audit page ID. When provided, re-audits the page within its site audit context, updating the auditPages row and recalculating the parent audit score.
                site_audit_id:
                  type: string
                  format: uuid
                  description: Optional site audit ID. Used together with audit_page_id to specify which site audit the page belongs to.
                site_id:
                  type: string
                  format: uuid
                  description: Optional site ID. When provided, the endpoint uses this site for routing instead of auto-detecting by domain.
                confirm_target_keyword_change:
                  type: boolean
                  description: Retry with true only after the user explicitly confirms replacing the page's canonical target keyword following a 409 response.
      responses:
        '201':
          description: 'Audit completed successfully (synchronous). Returned for routes: standalone, reaudit_in_site_audit, add_to_site_audit.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  route:
                    type: string
                    enum:
                    - standalone
                    - reaudit_in_site_audit
                    - add_to_site_audit
                    description: The routing path taken by the endpoint.
                  id:
                    type: string
                    format: uuid
                  url:
                    type: string
                    format: uri
                  status:
                    type: string
                    enum:
                    - completed
                    - failed
                  keyword:
                    type: string
                    nullable: true
                  content_type:
                    type: string
                    nullable: true
                    description: Canonical content type. Null when classification is not applicable or unmeasured.
                    enum:
                    - blog_post
                    - page
                    - faq
                    - glossary
                    - comparison
                    - pillar
                    - how_to
                    - landing
                    - listicle
                    - case_study
                    - tutorial
                    - news
                    - product_update
                    - data_report
                    - event
                    - resource
                    - alternative
                    - tool_review
                    - null
                  content_type_confidence:
                    type: string
                    nullable: true
                    description: Categorical confidence in the canonical content classification.
                    enum:
                    - high
                    - medium
                    - low
                    - null
                  content_type_status:
                    type: string
                    description: Whether canonical classification succeeded, used a deterministic fallback, was not applicable, or was unmeasured.
                    enum:
                    - classified
                    - fallback
                    - not_applicable
                    - unmeasured
                  content_type_method:
                    type: string
                    nullable: true
                    description: Classification method. Null when no classifier ran.
                    enum:
                    - llm
                    - deterministic
                    - null
                  content_type_version:
                    type: string
                    nullable: true
                    description: Internal classifier revision. Null when no classifier ran.
                  title:
                    type: string
                    nullable: true
                  meta_description:
                    type: string
                    nullable: true
                  word_count:
                    type: integer
                  overall_score:
                    type: integer
                    nullable: true
                    minimum: 0
                    maximum: 100
                  eeat_score:
                    type: integer
                    nullable: true
                    minimum: 0
                    maximum: 100
                  eeat_breakdown:
                    type: object
                    nullable: true
                  geo_score:
                    type: integer
                    nullable: true
                    minimum: 0
                    maximum: 100
                  geo_breakdown:
                    type: object
                    nullable: true
                  seo_score:
                    type: integer
                    nullable: true
                    minimum: 0
                    maximum: 100
                  seo_breakdown:
                    type: object
                    nullable: true
                  issues:
                    type: array
                    items:
                      type: object
                  headings:
                    type: array
                    items:
                      type: object
                      properties:
                        level:
                          type: integer
                        text:
                          type: string
                  outbound_links:
                    type: array
                    items:
                      type: string
                  author_name:
                    type: string
                    nullable: true
                  analyzed_at:
                    type: string
                    format: date-time
                  created_at:
                    type: string
                    format: date-time
        '409':
          description: Target keyword conflict. Confirm the change with the user, then retry with confirm_target_keyword_change=true.
        '422':
          description: Invalid URL
        '429':
          description: Audit page limit exceeded
components:
  schemas:
    Pagination:
      type: object
      properties:
        page:
          type: integer
        page_size:
          type: integer
        total:
          type: integer
        has_more:
          type: boolean
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: 'API key for authentication. Get your key from Settings > API Keys. You may also send the same key as `Authorization: Bearer <key>` — see BearerAuth.'
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Frase API key (sk_live_* / sk_test_*) or MCP access token (mcp_at_*)
      description: 'Send either your API key or an MCP access token as `Authorization: Bearer <token>`. An API key sent this way is exactly equivalent to sending it in X-API-KEY — same identity, same scopes, same rate limits — so use whichever your HTTP client makes natural. X-API-KEY takes precedence if you somehow send both. Cookie/session auth is intentionally NOT supported on /api/v1/* endpoints.'