Onto Read + Score API

One call, both outputs — Markdown plus the scoring metadata.

Operations 1

POST /v1/read-and-score Read and score a URL in a single call #

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/buildonto-dev:buildonto-dev-read-score-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

buildonto-dev-read-score-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Onto Read Read + Score API
  version: 1.0.0
  summary: Turn any URL into clean Markdown, an AIO accuracy score, and hallucination-risk flags.
  description: 'The Onto Read API takes a URL and returns clean Markdown that an LLM can consume directly,

    plus a 0–100 AIO accuracy score and hallucination-risk metadata.


    **Authentication.** All requests use bearer-token auth — pass your API key in the

    `Authorization` header. Get one at app.buildonto.dev/read/keys;

    the Free tier gives you 1,000 credits a month.


    **Endpoints.** `/v1/read`, `/v1/score`, `/v1/read-and-score` and `/v1/extract` work on one

    URL. `/v1/batch` handles up to 50 URLs in one call, `/v1/map` lists a site''s URLs, and

    `/v1/usage` shows your quota and credits. Most agent workflows want `/v1/read-and-score` —

    it returns both the cleaned Markdown and the accuracy metadata in a single round-trip.


    **Credits.** `/v1/read`, `/v1/read-and-score`, `/v1/extract` and `/v1/map` cost 1 credit per

    call; `/v1/batch` costs 1 credit per URL. `/v1/score` and `/v1/usage` are free. Failed

    requests are refunded.


    **Errors.** Every error response shares the same shape with a stable `code` field — branch

    on `code`, not on the human-readable `message`. Extra details, like `retry_after`, sit at

    the top level of the body. See

    the error codes index for the full catalog.'
  contact:
    name: Onto support
    email: founder@buildonto.dev
    url: https://buildonto.dev
  license:
    name: Proprietary
    url: https://buildonto.dev/legal/terms
servers:
- url: https://api.buildonto.dev
  description: Production
security:
- bearerAuth: []
tags:
- name: Read + Score
  description: One call, both outputs — Markdown plus the scoring metadata.
paths:
  /v1/read-and-score:
    post:
      tags:
      - Read + Score
      summary: Read and score a URL in a single call
      operationId: readAndScore
      description: 'Combines `/v1/read` and `/v1/score` into one request. Returns clean Markdown plus

        the full AIO scoring metadata. This is the recommended endpoint for agent workflows

        — let the model decide based on both the content and its accuracy score.


        Costs 1 credit, not two. Same one-hour cache as `/v1/read`. For a PDF or plain-text

        URL, `aio_score`, `grade` and `hallucination_risk` are null.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReadRequest'
            example:
              url: https://stripe.com/pricing
      responses:
        '200':
          description: Successful read + score
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReadAndScoreResponse'
              example:
                status: success
                url: https://stripe.com/pricing
                markdown: '# Stripe Pricing


                  > Integrated per-transaction pricing…'
                metadata:
                  title: Stripe Pricing
                  description: Integrated per-transaction pricing with no setup fees or monthly fees.
                  language: en
                aio_score: 65
                grade: Needs work
                hallucination_risk: medium
                insights:
                  robots_allowed: true
                  waf_blocked: false
                  markdown_supported: false
                  json_ld_present: true
                  semantic_hierarchy: true
                penalties:
                - 'Critical: No Machine-Readable (Markdown) layer detected.'
                - 'Warning: Page size is very high (612KB).'
                benefits:
                - 'Metadata Extraction: Onto distills explicit JSON-LD schema.'
                recommendations:
                - title: Install @ontosdk/next
                  description: Zero change required to application code. Automates Markdown extraction at build-time.
                  priority: High
                stats:
                  raw_html_size_kb: 612.4
                  markdown_size_kb: 14.2
                  reduction_percent: 97.7
                  extraction_time_ms: 1410
                cache:
                  hit: false
                  ttl_seconds: 3600
        '400':
          $ref: '#/components/responses/InvalidUrl'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/UrlNotFound'
        '413':
          $ref: '#/components/responses/TooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedType'
        '422':
          $ref: '#/components/responses/ImagePdf'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ExtractionFailed'
        '502':
          $ref: '#/components/responses/TlsError'
        '504':
          $ref: '#/components/responses/Timeout'
components:
  responses:
    UnsupportedType:
      description: '`UNSUPPORTED_TYPE` — the URL isn''t HTML, PDF or text (for example an image, video or archive).'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: UNSUPPORTED_TYPE
            message: Not a readable document (image/png). Onto reads HTML, PDF, and text formats.
    Timeout:
      description: Target site took longer than 15 seconds to respond.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: TIMEOUT
            message: Target site took too long to respond
    TooLarge:
      description: '`TOO_LARGE` — the document is over 10 MB.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: TOO_LARGE
            message: Document exceeds the read limit; Onto reads up to 10MB
    Unauthorized:
      description: Missing, malformed, or revoked Bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: UNAUTHORIZED
            message: Missing or invalid API key
    ExtractionFailed:
      description: '`EXTRACTION_FAILED` — the origin returned an error status other than 401/403/404, the

        host refused the connection or was unreachable, there were more than 5 redirects or a

        bad redirect, or the page or PDF couldn''t be parsed. Retry once; errors are never cached.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: EXTRACTION_FAILED
            message: Upstream returned HTTP 503
    RateLimited:
      description: 'Multiple causes:

        - `RATE_LIMITED` — monthly plan credits used up (Free only; paid plans spill into bought credits)

        - `CONCURRENT_LIMIT` — too many requests running at once for your plan; retry after 1 second

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            monthly:
              value:
                status: error
                code: RATE_LIMITED
                message: Monthly quota exceeded
                retry_after: '2026-10-01T00:00:00.000Z'
            concurrent:
              value:
                status: error
                code: CONCURRENT_LIMIT
                message: Too many concurrent requests for your tier (5/5 in flight). Retry in a moment.
                in_flight: 5
                limit: 5
                retry_after: 1
    UrlNotFound:
      description: Target URL returned 404, or its hostname doesn't resolve.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: URL_NOT_FOUND
            message: 'Target URL returned 404: https://example.com/old-page'
    PaymentRequired:
      description: Paid plans only — monthly plan credits AND bought credits are both used up. Free gets `RATE_LIMITED` instead.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: PAYMENT_REQUIRED
            message: Monthly plan quota exceeded and credit balance is empty. Top up credits in the dashboard to continue.
            plan_limit: 10000
            credits_remaining: 0
    ImagePdf:
      description: '`IMAGE_PDF` — a scanned PDF with no text layer. Onto does not OCR.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: IMAGE_PDF
            message: This PDF has no extractable text (likely scanned or image-only). Onto does not OCR.
    Forbidden:
      description: 'Multiple causes:

        - `WAF_BLOCKED` — target site refused our crawler (origin returned 401/403)

        - `ROBOTS_BLOCKED` — target site''s robots.txt has `Disallow: /` for GPTBot or `*`

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            waf:
              value:
                status: error
                code: WAF_BLOCKED
                message: Target site refused our crawler (HTTP 403)
            robots:
              value:
                status: error
                code: ROBOTS_BLOCKED
                message: Target site's robots.txt disallows AI crawlers. We honor robots.txt — see https://buildonto.dev/about-bot.
    InvalidUrl:
      description: '`INVALID_URL` — body isn''t JSON, `url` is missing or unparseable, the scheme isn''t

        http(s), or the URL points at a private or internal host.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: INVALID_URL
            message: '"url" field is required'
    TlsError:
      description: '`TLS_ERROR` — the target site''s TLS certificate or handshake failed.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            code: TLS_ERROR
            message: Target site has an invalid TLS certificate (CERT_HAS_EXPIRED)
  schemas:
    Metadata:
      type: object
      properties:
        title:
          type: string
        description:
          type: string
        language:
          type: string
          description: ISO 639-1 language code if detected.
    Recommendation:
      type: object
      required:
      - title
      - description
      - priority
      properties:
        title:
          type: string
        description:
          type: string
        priority:
          type: string
          enum:
          - High
          - Medium
          - Low
    CacheInfo:
      type: object
      required:
      - hit
      - ttl_seconds
      properties:
        hit:
          type: boolean
        ttl_seconds:
          type: integer
          description: Cache TTL applied to this response (currently 3600).
    ErrorResponse:
      type: object
      required:
      - status
      - code
      - message
      properties:
        status:
          type: string
          enum:
          - error
        code:
          type: string
          description: Stable error code — branch on this, not on `message`.
        message:
          type: string
          description: Human-readable message; wording may change without notice.
        retry_after:
          oneOf:
          - type: integer
            description: Seconds to wait before retrying (CONCURRENT_LIMIT). Always 1.
          - type: string
            format: date-time
            description: When monthly credits reset — the end of the current UTC month (RATE_LIMITED).
        plan_limit:
          type: integer
          description: Your plan's monthly credits (PAYMENT_REQUIRED).
        credits_remaining:
          type: integer
          description: Bought credits left, always 0 (PAYMENT_REQUIRED).
        in_flight:
          type: integer
          description: Requests running for your account right now (CONCURRENT_LIMIT).
        limit:
          type: integer
          description: Your plan's concurrency limit (CONCURRENT_LIMIT).
    ReadRequest:
      type: object
      required:
      - url
      properties:
        url:
          type: string
          format: uri
          description: Absolute URL to read. Must include scheme (`http://` or `https://`).
          example: https://stripe.com/pricing
        fresh:
          type: boolean
          default: false
          description: Bypass the one-hour cache and re-fetch from origin.
    ReadResponse:
      type: object
      required:
      - status
      - url
      - markdown
      - metadata
      - stats
      - cache
      properties:
        status:
          type: string
          enum:
          - success
        url:
          type: string
          format: uri
        markdown:
          type: string
          description: Clean, agent-ready Markdown extracted from the target URL.
        metadata:
          $ref: '#/components/schemas/Metadata'
        stats:
          $ref: '#/components/schemas/ReadStats'
        warnings:
          type: array
          items:
            type: string
          description: 'Sent by `/v1/read` only when there is something to flag — for example, a page that

            yielded very little text and most likely renders its content with JavaScript, which

            Onto does not execute.

            '
        cache:
          $ref: '#/components/schemas/CacheInfo'
    ReadStats:
      type: object
      required:
      - raw_html_size_kb
      - markdown_size_kb
      - reduction_percent
      - extraction_time_ms
      properties:
        raw_html_size_kb:
          type: number
        markdown_size_kb:
          type: number
        reduction_percent:
          type: number
          description: How much smaller the Markdown is vs. the raw HTML (0–100).
        extraction_time_ms:
          type: integer
    ScoringInsights:
      type: object
      required:
      - robots_allowed
      - waf_blocked
      - markdown_supported
      - json_ld_present
      - semantic_hierarchy
      properties:
        robots_allowed:
          type: boolean
        waf_blocked:
          type: boolean
        markdown_supported:
          type: boolean
        json_ld_present:
          type: boolean
        semantic_hierarchy:
          type: boolean
    ReadAndScoreResponse:
      allOf:
      - $ref: '#/components/schemas/ReadResponse'
      - type: object
        required:
        - aio_score
        - grade
        - hallucination_risk
        - insights
        - penalties
        - benefits
        - recommendations
        properties:
          aio_score:
            type:
            - integer
            - 'null'
            minimum: 0
            maximum: 100
            description: Null for PDF and plain-text URLs.
          grade:
            type:
            - string
            - 'null'
            enum:
            - Excellent
            - Good
            - Needs work
            - AI-hostile
            - Invisible
            - null
          hallucination_risk:
            type:
            - string
            - 'null'
            enum:
            - low
            - medium
            - high
            - null
          insights:
            $ref: '#/components/schemas/ScoringInsights'
          penalties:
            type: array
            items:
              type: string
          benefits:
            type: array
            items:
              type: string
          recommendations:
            type: array
            items:
              $ref: '#/components/schemas/Recommendation'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: onto_sk_live_…
      description: 'Pass your API key as `Authorization: Bearer {your_key}`. Get a key at

        [app.buildonto.dev/read/keys](https://app.buildonto.dev/read/keys).

        '