API reference

Validate JSON against a JSON Schema

Validate a JSON instance against a JSON Schema (draft 2020-12, 2019-09, 7, 6 or 4) and list every error with JSON Pointers.

GET POST /api/json/schema/validate MCP tool json_schema_validate

Validates instance against schema with @cfworker/json-schema (an interpreter: no code generation). The draft comes from draft, else from the schema's $schema, else 2020-12. Returns valid and, for an invalid instance, each error with the instance location and keyword location as JSON Pointers, the location of the keyword in the schema document (after following $ref), and a message; leaf: false marks summary errors (from properties, items, $ref, anyOf, …) that are followed by the specific errors beneath them. An invalid instance is a successful response with valid: false. Before validating, the schema is checked for usability (keyword types, regular expressions, unresolved references); problems are a 422 error. Only local references resolve: $ref to a remote URL is never fetched (the server makes no network requests); embed such schemas under $defs with their $id. format is asserted for the formats listed in the docs. $dynamicRef is not supported. At most 1000 errors are returned.

Browser version (runs locally): JSON Schema Validator.

Try it

Credentials
Remember these credentials

Not saved: you will paste them again next time.

No credentials yet? Get a client ID and secret. They are sent only to this site, in an Authorization: Basic header.

POST /api/json/schema/validate with a JSON body

Parameters

Parameter Type Default Description
schema required string (≤ 100000 chars) — The JSON Schema, as JSON text (an object or a boolean).
instance required string (≤ 200000 chars) — The JSON document to validate, as JSON text.
draft auto | 2020-12 | 2019-09 | 7 | 4 auto auto uses the draft named by the schema's $schema (draft 6 is validated as 7) and 2020-12 if there is none. Otherwise 2020-12, 2019-09, 7 or 4 overrides $schema.
all_errors boolean true true reports every error. false stops at the first failing keyword (faster; valid is the same either way).

Also accepted on every endpoint: format (json | text). Parameters may come from the query string, a JSON object body, an urlencoded or multipart form, or (for input) a text/plain body.

Global parameters
Parameter Type Default Description
format json | text json json returns the documented object. text returns only the primary value as text/plain (see "Text output").

Response 200 application/json

Field Type Description
valid boolean True when the instance satisfies the schema.
draft "2020-12" | "2019-09" | "7" | "4" The draft used.
draftSource "parameter" | "$schema" | "default" Where the draft came from.
errorCount integer Total number of errors, including any beyond the listed maximum.
errors array of object Errors in evaluation order (at most 1000).
errors[].instanceLocation string JSON Pointer to the failing value in the instance; "" is the whole document.
errors[].keyword string The schema keyword that failed, e.g. type, required, minimum; false for a false schema.
errors[].keywordLocation string Evaluation path through the schema as a JSON Pointer; a $ref segment marks a followed reference.
errors[].schemaLocation string | null JSON Pointer to the keyword in the schema document, after following $ref; null if it cannot be resolved ($recursiveRef).
errors[].message string What is wrong.
errors[].leaf boolean False for a summary error that is followed by the more specific errors that caused it.
warnings array of object Things that did not stop validation but may not do what you expect.
warnings[].source "schema" | "instance" Which document the warning is about.
warnings[].pointer string JSON Pointer in that document.
warnings[].message string Ignored or unknown keywords, unchecked formats, draft mismatches, duplicate keys, lossy numbers.

Text output (format=text, text/plain): valid, or invalid followed by one line per leaf error: <instanceLocation or /> <message>.

Errors

Errors are JSON: {"error": "<message>", "code": "<code>", "param": "<name>"?}.

Status Code When
422 unprocessable_input schema or instance is not valid JSON (the message gives line, column and offset), or the schema is not usable: a keyword has the wrong type, a regular expression does not compile, a $ref does not resolve locally, the draft is 3, or $ref cycles never reach the instance.
400 invalid_parameter schema or instance exceeds its length limit, or draft is not a listed value.
400 missing_parameter A required parameter is absent.
400 unknown_parameter A parameter name is not in the table above (typos are rejected, not ignored).
413 payload_too_large The request body exceeds 1 MiB.
405 method_not_allowed A method other than GET, POST or OPTIONS.

Behaviour

  • Idempotent: the same arguments always return the same result.
  • Requires a client ID and secret (authentication). Each call is recorded as one metadata row against your client ID; inputs and outputs are never stored or logged. Responses carry cache-control: no-store.
  • CORS: any origin may call this endpoint from a browser, using your credentials.

Examples

Responses below were produced by running each request through this code at build time. Long strings are shortened.

An instance with several errors

curl -X POST 'https://util.caruana.me/api/json/schema/validate' \
  -H 'content-type: application/json' \
  -d '{"schema":"{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"required\":[\"id\",\"email\"],\"properties\":{\"id\":{\"type\":\"integer\",\"minimum\":1},\"email\":{\"type\":\"string\",\"format\":\"email\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true}},\"additionalProperties\":false}","instance":"{\"id\":0,\"tags\":[\"a\",\"a\"],\"extra\":true}"}'

Response 200

{
  "valid": false,
  "draft": "2020-12",
  "draftSource": "$schema",
  "errorCount": 7,
  "errors": [
    {
      "instanceLocation": "",
      "keyword": "required",
      "keywordLocation": "/required",
      "schemaLocation": "/required",
      "message": "Instance does not have required property \"email\".",
      "leaf": true
    },
    {
      "instanceLocation": "",
      "keyword": "properties",
      "keywordLocation": "/properties",
      "schemaLocation": "/properties",
      "message": "Property \"id\" does not match schema.",
      "leaf": false
    },
    {
      "instanceLocation": "/id",
      "keyword": "minimum",
      "keywordLocation": "/properties/id/minimum",
      "schemaLocation": "/properties/id/minimum",
      "message": "0 is less than 1.",
      "leaf": true
    },
    {
      "instanceLocation": "",
      "keyword": "properties",
      "keywordLocation": "/properties",
      "schemaLocation": "/properties",
      "message": "Property \"tags\" does not match schema.",
      "leaf": false
    },
    {
      "instanceLocation": "/tags",
      "keyword": "uniqueItems",
      "keywordLocation": "/properties/tags/uniqueItems",
      "schemaLocation": "/properties/tags/uniqueItems",
      "message": "Duplicate items at indexes 0 and 1.",
      "leaf": true
    },
    {
      "instanceLocation": "",
      "keyword": "additionalProperties",
      "keywordLocation": "/additionalProperties",
      "schemaLocation": "/additionalProperties",
      "message": "Property \"extra\" does not match additional properties schema.",
      "leaf": false
    },
    {
      "instanceLocation": "/extra",
      "keyword": "false",
      "keywordLocation": "/additionalProperties",
      "schemaLocation": "/additionalProperties",
      "message": "The schema here is false: no value is allowed at this location.",
      "leaf": true
    }
  ],
  "warnings": []
}
Same call as an MCP tools/call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "json_schema_validate",
    "arguments": {
      "schema": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"required\":[\"id\",\"email\"],\"properties\":{\"id\":{\"type\":\"integer\",\"minimum\":1},\"email\":{\"type\":\"string\",\"format\":\"email\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"uniqueItems\":true}},\"additionalProperties\":false}",
      "instance": "{\"id\":0,\"tags\":[\"a\",\"a\"],\"extra\":true}"
    }
  }
}

Valid, with a local $ref

curl -X POST 'https://util.caruana.me/api/json/schema/validate' \
  -H 'content-type: application/json' \
  -d '{"schema":"{\"$defs\":{\"port\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":65535}},\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/port\"}}","instance":"[80, 443]"}'

Response 200

{
  "valid": true,
  "draft": "2020-12",
  "draftSource": "default",
  "errorCount": 0,
  "errors": [],
  "warnings": []
}
Same call as an MCP tools/call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "json_schema_validate",
    "arguments": {
      "schema": "{\"$defs\":{\"port\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":65535}},\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/port\"}}",
      "instance": "[80, 443]"
    }
  }
}