{
  "openapi": "3.1.0",
  "info": {
    "title": "Diffchecker API",
    "version": "1.0.0",
    "termsOfService": "https://www.diffchecker.com/terms/",
    "contact": {
      "name": "Diffchecker Support",
      "url": "https://www.diffchecker.com/contact/"
    },
    "license": {
      "name": "Diffchecker API License and Services Agreement",
      "url": "https://www.diffchecker.com/api-lsa/"
    },
    "description": "The Diffchecker API provides HTTP endpoints for comparing text, PDF and Word documents, images, and Excel spreadsheets. Document endpoints include PDF plain-text and rich-text comparisons plus DOCX redlines with Microsoft Word tracked changes.\n\nCanonical PDF comparison routes use `/document/plaintext` and `/document/richtext`. The legacy `/pdf`, `/pdf/plaintext`, and `/pdf/richtext` routes remain supported for compatibility.\n\n## Authentication\n\nThere are two ways of interacting with the Diffchecker API:\n\n- **Email**: Just pass your email as a query string parameter. This method does not require you to have a Diffchecker account and will allow you to make as many diffs as free tier limits allow.\n- **API Key**: Every paid subscriber gets their own API key, which needs to be passed as the request's `X-Api-Key` header. This will allow you to make as many diffs as your paid plan allows.\n\nWhen both are provided, email gets ignored in favor of the API key. The examples in these docs assume you are authenticating via email.\n\n## Rate Limiting\n\nAPI requests are rate-limited based on your authentication method. Free tier (email) users have lower limits than paid subscribers using an API key. If you exceed the rate limit, the API will return a `429 Too Many Requests` response.\n\nEvery public API response includes an `X-Credits-Used` response header. For backwards compatibility, JSON responses also continue to include the same value in the `creditsUsed` response body field.\n\nSome `429` responses are returned for exhausted free or paid diff quotas. Zero-credit failed requests are also throttled separately and may include a `retryAfterSeconds` field in the JSON body.\n\n## Errors\n\nEvery failure is answered with JSON — never an HTML error page — using the same envelope as a successful response:\n\n```json\n{\n  \"creditsUsed\": 0,\n  \"error\": {\n    \"status\": 400,\n    \"code\": \"VALIDATION_ERROR\",\n    \"message\": \"One or more validation errors occurred.\",\n    \"hint\": \"Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.\",\n    \"documentation\": \"https://www.diffchecker.com/docs/getting-started\"\n  }\n}\n```\n\n- `status` repeats the HTTP status code, so a logged or forwarded `error` object stays self-describing.\n- `code` is stable and machine-readable — branch on it rather than on `message`.\n- `message` describes what went wrong.\n- `hint` gives a concrete next step that resolves the error.\n- `documentation` links to this reference.\n- `details` is present on some errors with structured, error-specific context.\n\nThis holds for every status the API can return, including unknown paths (`404 NOT_FOUND`), unsupported methods (`405 METHOD_NOT_ALLOWED`, with an `Allow` response header), unsupported request bodies (`415 UNSUPPORTED_MEDIA_TYPE`) and unexpected server failures (`500 INTERNAL_SERVER_ERROR`). Every operation documents those four responses.\n\nA request body whose Content-Type the endpoint does not accept is rejected with `415 UNSUPPORTED_MEDIA_TYPE` before any endpoint logic runs. `/text` accepts only `application/json`; the upload endpoints accept `application/json` and `multipart/form-data`. A body of an accepted type that does not match the `input_type` query parameter (for example a JSON body with `input_type=form`) is not a 415: the endpoint finds no inputs and answers `400 INVALID_INPUT`.\n\nMalformed multipart bodies on `/document/plaintext`, `/document/richtext`, `/image` and `/excel` (and the legacy `/pdf` routes) return `400 INVALID_MULTIPART`. Send a complete body with a boundary matching the Content-Type header; let your HTTP client generate the header and boundary together. Recognized upload errors retain their specific codes, such as `LIMIT_UNEXPECTED_FILE`, `INVALID_FILE_EXTENSION` and `LIMIT_FILE_SIZE`. `/document/redline` uses its own DOCX parser and reports the same condition as `400 INVALID_DOCX_UPLOAD`.\n\n## Resources\n\nYou may find the following resources helpful when dealing with PDF, Image, or Excel diffs:\n\n- [Data URLs (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs)\n- [FormData (MDN)](https://developer.mozilla.org/en-US/docs/Web/API/FormData)\n"
  },
  "externalDocs": {
    "description": "Diffchecker API documentation",
    "url": "https://www.diffchecker.com/docs/getting-started/"
  },
  "servers": [
    {
      "url": "https://api.diffchecker.com/public",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    },
    {
      "email": []
    }
  ],
  "paths": {
    "/auth-test": {
      "get": {
        "operationId": "authTest",
        "summary": "Test authentication",
        "description": "Verify that your authentication credentials are working correctly.",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          }
        ],
        "responses": {
          "200": {
            "description": "Authentication is working correctly.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "creditsUsed": {
                      "type": "integer",
                      "example": 0
                    },
                    "message": {
                      "type": "string",
                      "example": "Auth is working correctly."
                    }
                  },
                  "required": [
                    "creditsUsed",
                    "message"
                  ]
                },
                "example": {
                  "creditsUsed": 0,
                  "message": "Auth is working correctly."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/text": {
      "post": {
        "operationId": "textDiff",
        "summary": "Compare Text",
        "description": "Compute a diff between two text strings with configurable output formats.",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          },
          {
            "name": "output_type",
            "in": "query",
            "required": true,
            "description": "Specifies the type of output you receive in the response body.\n- `json`: Row metadata generated from diff computation (Content-Type: application/json)\n- `html`: Same HTML/CSS you see on the Diffchecker site (Content-Type: text/html)\n- `html_json`: Same HTML/CSS you see on the Diffchecker site, but split up and embedded in JSON (Content-Type: application/json)\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html",
                "html_json"
              ]
            }
          },
          {
            "name": "diff_level",
            "in": "query",
            "required": false,
            "description": "Specifies whether you want to diff by word or character. Default is `word`.",
            "schema": {
              "type": "string",
              "enum": [
                "word",
                "character"
              ],
              "default": "word"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "left",
                  "right"
                ],
                "properties": {
                  "left": {
                    "type": "string",
                    "description": "Left text you want to diff."
                  },
                  "right": {
                    "type": "string",
                    "description": "Right text you want to diff."
                  }
                }
              },
              "example": {
                "left": "roses are red\nviolets are blue",
                "right": "roses are green\nviolets are purple"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diff computed successfully.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TextDiffJsonResponse"
                    },
                    {
                      "$ref": "#/components/schemas/HtmlJsonResponse"
                    }
                  ]
                },
                "examples": {
                  "json": {
                    "summary": "output_type=json",
                    "value": {
                      "creditsUsed": 1,
                      "rows": [
                        {
                          "end": false,
                          "left": {
                            "chunks": [
                              {
                                "value": "roses are ",
                                "type": "equal"
                              },
                              {
                                "value": "red",
                                "type": "remove"
                              }
                            ],
                            "line": 1
                          },
                          "right": {
                            "chunks": [
                              {
                                "value": "roses are ",
                                "type": "equal"
                              },
                              {
                                "value": "green",
                                "type": "insert"
                              }
                            ],
                            "line": 1
                          },
                          "insideChanged": true,
                          "start": true
                        },
                        {
                          "end": true,
                          "left": {
                            "chunks": [
                              {
                                "value": "",
                                "type": "remove"
                              },
                              {
                                "value": "violets are ",
                                "type": "equal"
                              },
                              {
                                "value": "blue",
                                "type": "remove"
                              }
                            ],
                            "line": 2
                          },
                          "right": {
                            "chunks": [
                              {
                                "value": "",
                                "type": "insert"
                              },
                              {
                                "value": "violets are ",
                                "type": "equal"
                              },
                              {
                                "value": "purple",
                                "type": "insert"
                              }
                            ],
                            "line": 2
                          },
                          "insideChanged": true
                        }
                      ],
                      "added": 3,
                      "removed": 3
                    }
                  },
                  "html_json": {
                    "summary": "output_type=html_json",
                    "value": {
                      "creditsUsed": 1,
                      "html": "<table class=\"diff-table\">...</table>",
                      "css": ".diff-table { font-family: monospace; ... }"
                    }
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "Full HTML with embedded CSS for the diff table."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/document/redline": {
      "post": {
        "operationId": "documentRedline",
        "summary": "Compare Documents (Redline)",
        "description": "Upload an original DOCX (`left_docx`) and a revised DOCX (`right_docx`) as multipart/form-data. The response is a DOCX based on the revised document with differences represented as Microsoft Word tracked changes.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "left_docx",
                  "right_docx"
                ],
                "properties": {
                  "left_docx": {
                    "type": "string",
                    "format": "binary",
                    "description": "Original Word document. The uploaded filename must end in .docx."
                  },
                  "right_docx": {
                    "type": "string",
                    "format": "binary",
                    "description": "Revised Word document. The uploaded filename must end in .docx."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid revised-document-based DOCX containing tracked changes. Usage has committed before delivery starts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              },
              "Content-Disposition": {
                "description": "Attachment filename for the generated redline.",
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"redline.docx\""
                }
              },
              "Content-Length": {
                "description": "Exact generated DOCX byte count.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart shape, filename, or DOCX package.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missing_files": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "MISSING_DOCX_FILES",
                        "message": "Both left_docx and right_docx are required exactly once.",
                        "hint": "Send both DOCX files as multipart/form-data parts named \"left_docx\" and \"right_docx\".",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_upload": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_DOCX_UPLOAD",
                        "message": "Uploaded filenames must end in .docx.",
                        "hint": "Send only the two DOCX file parts as multipart/form-data, with no query parameters other than \"email\".",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_docx": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_DOCX",
                        "message": "The uploaded file is not a valid DOCX package.",
                        "hint": "Confirm both uploads are valid .docx files, then retry. Legacy .doc files are not supported.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "password_protected_or_legacy": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "DOCX_PASSWORD_PROTECTED_OR_LEGACY",
                        "message": "Password-protected or legacy Word documents are not supported.",
                        "hint": "Remove the password or re-save the document in the modern .docx format, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "408": {
            "description": "Started redline processing exceeded its execution deadline.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 408,
                    "code": "REDLINE_TIMEOUT",
                    "message": "Redline processing timed out.",
                    "hint": "Retry with smaller or simpler documents. Very large documents can exceed the processing deadline.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          },
          "413": {
            "description": "Compressed input, expanded package, worker resources, or generated output exceeded its safety limit.\nThe two DOCX files may total at most 50 MB combined on any plan, and at most the plan's request size limit below that.\nExpanded-package structural limits include a combined maximum of 3,000 WordprocessingML paragraphs across both uploaded DOCX files.\n",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "compressed_input": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 413,
                        "code": "LIMIT_FILE_SIZE",
                        "message": "The combined DOCX upload exceeds the allowed request size.",
                        "hint": "The two DOCX files must total at most 50 MB combined, regardless of plan. Split the comparison into smaller documents.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "expanded_content": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 413,
                        "code": "DOCX_EXPANDED_SIZE_LIMIT_EXCEEDED",
                        "message": "The DOCX package exceeds expanded-content safety limits.",
                        "hint": "The documents expand beyond the supported size once unpacked. Remove embedded media or split the comparison.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "worker_resources": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 413,
                        "code": "REDLINE_RESOURCE_LIMIT_EXCEEDED",
                        "message": "Redline processing exceeded its resource limit.",
                        "hint": "Compare smaller or simpler documents; this pair exceeds the resources allowed for one redline.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "generated_output": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 413,
                        "code": "REDLINE_OUTPUT_TOO_LARGE",
                        "message": "Generated redline output is too large.",
                        "hint": "The redline output exceeds the maximum response size. Compare smaller documents or narrower sections.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "description": "Unexpected redline processing failure, or an unexpected server failure.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "processing_failed": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "REDLINE_PROCESSING_FAILED",
                        "message": "Unexpected redline processing failure.",
                        "hint": "Retry only if creditsUsed is 0. A non-zero creditsUsed (also sent as the X-Credits-Used header) means this comparison was already charged and a retry would bill it again. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "unexpected_failure": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "INTERNAL_SERVER_ERROR",
                        "message": "The server encountered an unexpected error.",
                        "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Either redline capacity was unavailable or billing finalization could not be confirmed. `Retry-After` is present only for `REDLINE_CAPACITY_EXCEEDED`. It is absent for `PUBLIC_API_BILLING_UNAVAILABLE`; that outcome may be commit-ambiguous, so verify current usage before retrying.\n",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              },
              "Retry-After": {
                "description": "Seconds to wait after a capacity response. Absent for billing-unavailable responses.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/RetriableErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "capacity": {
                    "value": {
                      "creditsUsed": 0,
                      "retryAfterSeconds": 10,
                      "error": {
                        "status": 503,
                        "code": "REDLINE_CAPACITY_EXCEEDED",
                        "message": "Redline processing is at capacity. Please retry shortly.",
                        "hint": "Wait for the number of seconds in the \"Retry-After\" header, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "billing_unavailable": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 503,
                        "code": "PUBLIC_API_BILLING_UNAVAILABLE",
                        "message": "Billing finalization could not be confirmed. Verify current usage before retrying.",
                        "hint": "Check your current usage at https://www.diffchecker.com/account before retrying, so the request is not billed twice.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/document/plaintext": {
      "post": {
        "operationId": "documentDiff",
        "summary": "Compare Documents (Plain Text PDF)",
        "description": "Compute a plain-text diff between two PDF documents. Supports both multipart/form-data file uploads and JSON with base64-encoded data URLs.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          },
          {
            "name": "input_type",
            "in": "query",
            "required": false,
            "description": "Specifies the request content-type.\n- `form`: multipart/form-data (default)\n- `json`: application/json\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "form"
              ],
              "default": "form"
            }
          },
          {
            "name": "output_type",
            "in": "query",
            "required": true,
            "description": "Specifies the type of output you receive in the response body.\n- `json`: Row metadata generated from PDF-text diff computation (Content-Type: application/json)\n- `html`: Same HTML/CSS you see on the Diffchecker site for PDF-text diffs (Content-Type: text/html)\n- `html_json`: Same HTML/CSS, but split up and embedded in JSON (Content-Type: application/json)\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html",
                "html_json"
              ]
            }
          },
          {
            "name": "diff_level",
            "in": "query",
            "required": false,
            "description": "Specifies whether you want to diff by word or character. Default is `word`. Should only be used with PDF-text diff related output types.",
            "schema": {
              "type": "string",
              "enum": [
                "word",
                "character"
              ],
              "default": "word"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "left_pdf",
                  "right_pdf"
                ],
                "properties": {
                  "left_pdf": {
                    "type": "string",
                    "format": "binary",
                    "description": "Left PDF file you want to diff. File extension must be .pdf."
                  },
                  "right_pdf": {
                    "type": "string",
                    "format": "binary",
                    "description": "Right PDF file you want to diff. File extension must be .pdf."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "left_pdf",
                  "right_pdf"
                ],
                "properties": {
                  "left_pdf": {
                    "type": "string",
                    "description": "Data URL of the left PDF (data:application/pdf;base64,...)."
                  },
                  "right_pdf": {
                    "type": "string",
                    "description": "Data URL of the right PDF (data:application/pdf;base64,...)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diff computed successfully. Same response structure as Text diff.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TextDiffJsonResponse"
                    },
                    {
                      "$ref": "#/components/schemas/HtmlJsonResponse"
                    }
                  ]
                },
                "examples": {
                  "json": {
                    "summary": "output_type=json",
                    "value": {
                      "creditsUsed": 1,
                      "rows": [
                        {
                          "end": false,
                          "left": {
                            "chunks": [
                              {
                                "value": "The quick brown fox ",
                                "type": "equal"
                              },
                              {
                                "value": "jumps",
                                "type": "remove"
                              }
                            ],
                            "line": 1
                          },
                          "right": {
                            "chunks": [
                              {
                                "value": "The quick brown fox ",
                                "type": "equal"
                              },
                              {
                                "value": "leaps",
                                "type": "insert"
                              }
                            ],
                            "line": 1
                          },
                          "insideChanged": true,
                          "start": true
                        },
                        {
                          "end": true,
                          "left": {
                            "chunks": [
                              {
                                "value": "",
                                "type": "remove"
                              },
                              {
                                "value": "over the lazy dog.",
                                "type": "equal"
                              }
                            ],
                            "line": 2
                          },
                          "right": {
                            "chunks": [
                              {
                                "value": "",
                                "type": "insert"
                              },
                              {
                                "value": "over the lazy dog.",
                                "type": "equal"
                              }
                            ],
                            "line": 2
                          },
                          "insideChanged": false
                        }
                      ],
                      "added": 1,
                      "removed": 1
                    }
                  },
                  "html_json": {
                    "summary": "output_type=html_json",
                    "value": {
                      "creditsUsed": 1,
                      "html": "<table class=\"diff-table\">...</table>",
                      "css": ".diff-table { font-family: monospace; ... }"
                    }
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Validation error, malformed JSON, invalid form-data, or corrupt or password-protected PDF input.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "validation_error": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "VALIDATION_ERROR",
                        "message": "One or more validation errors occurred.",
                        "hint": "Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started",
                        "details": [
                          {
                            "msg": "Invalid value",
                            "param": "output_type",
                            "location": "query"
                          }
                        ]
                      }
                    }
                  },
                  "invalid_json": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_JSON",
                        "message": "The request body contains invalid JSON.",
                        "hint": "Send a syntactically valid JSON body with the Content-Type header set to application/json.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_left_pdf_json": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_INPUT",
                        "message": "Received invalid left pdf json.",
                        "hint": "Send both the left and right inputs: base64 data URLs in the JSON body when `input_type=json`, or file parts when `input_type=form`.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "corrupt_pdf": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_PDF",
                        "message": "Could not process PDF. File may be corrupted.",
                        "hint": "Confirm both inputs are valid, uncorrupted PDF files, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "password_protected_pdf": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "PDF_PASSWORD_PROTECTED",
                        "message": "Password-protected PDF. Decrypt before uploading.",
                        "hint": "Remove the password from the PDF and upload the decrypted file.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "408": {
            "description": "Request timed out.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 408,
                    "code": "REQUEST_TIMEOUT",
                    "message": "Request timed out.",
                    "hint": "Retry with smaller or simpler PDFs. Very large documents can exceed the processing deadline.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "description": "Unexpected PDF processing failure, or an unexpected server failure.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "processing_failed": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "PDF_PROCESSING_FAILED",
                        "message": "Unexpected PDF processing failure.",
                        "hint": "Retry only if creditsUsed is 0. A non-zero creditsUsed (also sent as the X-Credits-Used header) means this comparison was already charged and a retry would bill it again. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "unexpected_failure": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "INTERNAL_SERVER_ERROR",
                        "message": "The server encountered an unexpected error.",
                        "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/document/richtext": {
      "post": {
        "operationId": "documentRichTextDiff",
        "summary": "Compare Documents (Rich Text)",
        "description": "Compute a rich-text diff between two PDFs with polygon geometry and optional visual object comparisons. Supports multipart/form-data uploads and JSON with base64-encoded data URLs.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          },
          {
            "name": "output_type",
            "in": "query",
            "required": true,
            "description": "Specifies the response format.\n- `json`: Structured rich-text payload with polygons + page metadata (Content-Type: application/json)\n- `html`: Self-contained HTML (Content-Type: text/html)\n- `html_json`: HTML/CSS parts in JSON (Content-Type: application/json)\n- `pdf`: Binary PDF export with rich-text highlights (Content-Type: application/pdf)\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html",
                "html_json",
                "pdf"
              ]
            }
          },
          {
            "name": "input_type",
            "in": "query",
            "required": false,
            "description": "Specifies the request content-type.\n- `form`: multipart/form-data (default)\n- `json`: application/json\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "form"
              ],
              "default": "form"
            }
          },
          {
            "name": "diff_level",
            "in": "query",
            "required": false,
            "description": "Specifies whether to diff by word or character. Default is `word`.",
            "schema": {
              "type": "string",
              "enum": [
                "word",
                "character"
              ],
              "default": "word"
            }
          },
          {
            "name": "page_image_scale",
            "in": "query",
            "required": false,
            "description": "Rendering scale used for page image generation and geometry alignment.\nAllowed range is 0.25 to 4.\nFor non-pdf outputs, explicit values above a document-safe runtime maximum return 400.\n",
            "schema": {
              "type": "number",
              "minimum": 0.25,
              "maximum": 4,
              "default": 1
            }
          },
          {
            "name": "show_moves",
            "in": "query",
            "required": false,
            "description": "Include move detection in the diff. Default is `true`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          },
          {
            "name": "compare_font_family",
            "in": "query",
            "required": false,
            "description": "Compare font family style changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_font_size",
            "in": "query",
            "required": false,
            "description": "Compare font size style changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_font_color",
            "in": "query",
            "required": false,
            "description": "Compare text color style changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_regular_images",
            "in": "query",
            "required": false,
            "description": "Compare raster image changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_vector_graphics",
            "in": "query",
            "required": false,
            "description": "Compare vector graphic changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_form_xobjects",
            "in": "query",
            "required": false,
            "description": "Compare form XObject changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "compare_shading_objects",
            "in": "query",
            "required": false,
            "description": "Compare shading object changes. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "pdf_layout",
            "in": "query",
            "required": false,
            "description": "Layout used when `output_type=pdf`.\n- `split-view` (default)\n- `alternating`\n- `left-document`\n- `right-document`\n",
            "schema": {
              "type": "string",
              "enum": [
                "split-view",
                "alternating",
                "left-document",
                "right-document"
              ],
              "default": "split-view"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "left_pdf",
                  "right_pdf"
                ],
                "properties": {
                  "left_pdf": {
                    "type": "string",
                    "format": "binary",
                    "description": "Left PDF file you want to diff. File extension must be .pdf."
                  },
                  "right_pdf": {
                    "type": "string",
                    "format": "binary",
                    "description": "Right PDF file you want to diff. File extension must be .pdf."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "left_pdf",
                  "right_pdf"
                ],
                "properties": {
                  "left_pdf": {
                    "type": "string",
                    "description": "Data URL of the left PDF (data:application/pdf;base64,...)."
                  },
                  "right_pdf": {
                    "type": "string",
                    "description": "Data URL of the right PDF (data:application/pdf;base64,...)."
                  }
                }
              },
              "example": {
                "left_pdf": "data:application/pdf;base64,...",
                "right_pdf": "data:application/pdf;base64,..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rich-text diff computed successfully.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RichTextJsonResponse"
                    },
                    {
                      "$ref": "#/components/schemas/HtmlJsonResponse"
                    }
                  ]
                },
                "examples": {
                  "json": {
                    "summary": "output_type=json",
                    "value": {
                      "creditsUsed": 1,
                      "diff": {
                        "left": [
                          {
                            "id": 0,
                            "type": "remove",
                            "pageIndex": 0,
                            "text": [
                              "Left"
                            ],
                            "polygons": [
                              [
                                [
                                  72,
                                  720.64
                                ],
                                [
                                  72,
                                  706.03
                                ],
                                [
                                  90.33,
                                  706.03
                                ],
                                [
                                  90.33,
                                  720.64
                                ]
                              ]
                            ]
                          }
                        ],
                        "right": [
                          {
                            "id": 0,
                            "type": "insert",
                            "pageIndex": 0,
                            "text": [
                              "Right"
                            ],
                            "polygons": [
                              [
                                [
                                  72,
                                  720.64
                                ],
                                [
                                  72,
                                  706.03
                                ],
                                [
                                  97.65,
                                  706.03
                                ],
                                [
                                  97.65,
                                  720.64
                                ]
                              ]
                            ]
                          }
                        ],
                        "changeLog": [
                          {
                            "chunkId": 0,
                            "contentBefore": "Left",
                            "contentAfter": "Right",
                            "contentType": "text",
                            "type": "replace",
                            "pageIndex": 0
                          }
                        ]
                      },
                      "left": {
                        "pageCount": 1,
                        "pageDimensions": [
                          {
                            "width": 612,
                            "height": 792
                          }
                        ],
                        "rotations": [
                          0
                        ],
                        "pageImages": [
                          "data:image/png;base64,..."
                        ],
                        "pageImageScale": 1
                      },
                      "right": {
                        "pageCount": 1,
                        "pageDimensions": [
                          {
                            "width": 612,
                            "height": 792
                          }
                        ],
                        "rotations": [
                          0
                        ],
                        "pageImages": [
                          "data:image/png;base64,..."
                        ],
                        "pageImageScale": 1
                      }
                    }
                  },
                  "html_json": {
                    "summary": "output_type=html_json",
                    "value": {
                      "creditsUsed": 1,
                      "html": "<div class=\"rich-text-layout\">...</div>",
                      "css": "body { ... }"
                    }
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "Self-contained HTML with page images and SVG overlays."
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "PDF export with rich-text highlights."
                }
              }
            }
          },
          "400": {
            "description": "Validation error, malformed or password-protected PDF, or invalid page scale request.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "validation_error": {
                    "summary": "Invalid page_image_scale",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "VALIDATION_ERROR",
                        "message": "One or more validation errors occurred.",
                        "hint": "Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started",
                        "details": [
                          {
                            "msg": "page_image_scale must be between 0.25 and 4.",
                            "param": "page_image_scale",
                            "location": "query"
                          }
                        ]
                      }
                    }
                  },
                  "explicit_scale_too_high": {
                    "summary": "Explicit scale exceeds runtime safe max",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "PAGE_IMAGE_SCALE_UNSUPPORTED",
                        "message": "Requested page_image_scale=4 exceeds the document-safe max (1.5).",
                        "hint": "Retry with page_image_scale=1.5 or lower.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started",
                        "details": {
                          "requested": 4,
                          "max_supported": 1.5,
                          "left_max_supported": 2,
                          "right_max_supported": 1.5
                        }
                      }
                    }
                  },
                  "bitmap_render_error": {
                    "summary": "Page render failed at requested scale",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "PAGE_IMAGE_RENDER_FAILED",
                        "message": "Unable to render page images at the requested page_image_scale. Try a lower page_image_scale.",
                        "hint": "Retry with a lower `page_image_scale`, or omit it to use the default.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "corrupt_pdf": {
                    "summary": "Corrupt PDF input",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_PDF",
                        "message": "Could not process PDF. File may be corrupted.",
                        "hint": "Confirm both inputs are valid, uncorrupted PDF files, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "password_protected_pdf": {
                    "summary": "Password-protected PDF input",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "PDF_PASSWORD_PROTECTED",
                        "message": "Password-protected PDF. Decrypt before uploading.",
                        "hint": "Remove the password from the PDF and upload the decrypted file.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_left_pdf_json": {
                    "summary": "Invalid left PDF JSON payload",
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_INPUT",
                        "message": "Received invalid left pdf json.",
                        "hint": "Send both the left and right inputs: base64 data URLs in the JSON body when `input_type=json`, or file parts when `input_type=form`.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "408": {
            "description": "Request timed out.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 408,
                    "code": "REQUEST_TIMEOUT",
                    "message": "Request timed out.",
                    "hint": "Retry with smaller or simpler PDFs. Very large documents can exceed the processing deadline.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "description": "Unexpected PDF processing failure, or an unexpected server failure.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "processing_failed": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "PDF_PROCESSING_FAILED",
                        "message": "Unexpected PDF processing failure.",
                        "hint": "Retry only if creditsUsed is 0. A non-zero creditsUsed (also sent as the X-Credits-Used header) means this comparison was already charged and a retry would bill it again. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "unexpected_failure": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "INTERNAL_SERVER_ERROR",
                        "message": "The server encountered an unexpected error.",
                        "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/image": {
      "post": {
        "operationId": "imageDiff",
        "summary": "Compare Images",
        "description": "Compute a visual diff between two images. Supports both multipart/form-data file uploads and JSON with base64-encoded data URLs.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          },
          {
            "name": "input_type",
            "in": "query",
            "required": true,
            "description": "Specifies the request content-type.\n- `form`: multipart/form-data\n- `json`: application/json\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "form"
              ]
            }
          },
          {
            "name": "output_type",
            "in": "query",
            "required": true,
            "description": "Specifies the type of output you receive in the response body.\n- `json`: Same PNG you see on the Diffchecker site for image diffs, but embedded in JSON as a data URL (Content-Type: application/json)\n- `png`: Same PNG you see on the Diffchecker site for image diffs (Content-Type: image/png)\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "png"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "left_image",
                  "right_image"
                ],
                "properties": {
                  "left_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Left image file you want to diff. Accepted file extensions include .png, .jpg, .jpeg."
                  },
                  "right_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Right image file you want to diff. Accepted file extensions include .png, .jpg, .jpeg."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "left_image",
                  "right_image"
                ],
                "properties": {
                  "left_image": {
                    "type": "string",
                    "description": "Data URL of the left image you want to diff."
                  },
                  "right_image": {
                    "type": "string",
                    "description": "Data URL of the right image you want to diff."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diff computed successfully.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageDiffJsonResponse"
                },
                "example": {
                  "creditsUsed": 1,
                  "dataUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVAAAAS8CAYAAABqj6EYAAAABmJLR0QA...",
                  "diffPixels": 34651,
                  "totalPixels": 234600,
                  "misMatchPercentage": 14.77,
                  "width": 460,
                  "height": 510,
                  "originalWidth": 452,
                  "originalHeight": 477,
                  "changedWidth": 460,
                  "changedHeight": 510
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "PNG image of the visual diff."
                }
              }
            }
          },
          "400": {
            "description": "Invalid request data or image content.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "validation_error": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "VALIDATION_ERROR",
                        "message": "One or more validation errors occurred.",
                        "hint": "Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started",
                        "details": [
                          {
                            "msg": "Invalid value",
                            "param": "output_type",
                            "location": "query"
                          }
                        ]
                      }
                    }
                  },
                  "corrupt_image": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_IMAGE",
                        "message": "Could not process image. File may be corrupted.",
                        "hint": "Confirm both inputs are valid, uncorrupted image files in a supported format, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_json": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_JSON",
                        "message": "The request body contains invalid JSON.",
                        "hint": "Send a syntactically valid JSON body with the Content-Type header set to application/json.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_files_json": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_INPUT",
                        "message": "Received invalid files.",
                        "hint": "Send both the left and right inputs: base64 data URLs in the JSON body when `input_type=json`, or file parts when `input_type=form`.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "description": "Image comparison failed due to a server-side processing error, or an unexpected server failure.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_platform": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "IMAGE_COMPARISON_UNSUPPORTED",
                        "message": "Image comparison is not supported on this platform.",
                        "hint": "This is a server-side limitation, not a problem with your request. Contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "processing_failed": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "IMAGE_PROCESSING_FAILED",
                        "message": "Unexpected image processing failure.",
                        "hint": "Retry only if creditsUsed is 0. A non-zero creditsUsed (also sent as the X-Credits-Used header) means this comparison was already charged and a retry would bill it again. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "unexpected_failure": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "INTERNAL_SERVER_ERROR",
                        "message": "The server encountered an unexpected error.",
                        "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/excel": {
      "post": {
        "operationId": "excelDiff",
        "summary": "Compare Excel Spreadsheets",
        "description": "Compute a diff between two spreadsheets. Supports both multipart/form-data file uploads and JSON with base64-encoded data URLs. Accepts .xlsx, .xls, and .csv files.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/email"
          },
          {
            "name": "input_type",
            "in": "query",
            "required": true,
            "description": "Specifies the request content-type.\n- `form`: multipart/form-data\n- `json`: application/json\n",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "form"
              ]
            }
          },
          {
            "name": "diff_level",
            "in": "query",
            "required": false,
            "description": "Specifies whether you want to diff values by their formulas or standard values. Default is `standard`.",
            "schema": {
              "type": "string",
              "enum": [
                "standard",
                "formulas"
              ],
              "default": "standard"
            }
          },
          {
            "name": "ignore_whitespace",
            "in": "query",
            "required": false,
            "description": "Whether to ignore leading and trailing whitespace in the diff. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "ignore_case_changes",
            "in": "query",
            "required": false,
            "description": "Whether to ignore case changes in the diff. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "hide_unchanged_rows",
            "in": "query",
            "required": false,
            "description": "Whether to hide unchanged rows in the diff. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "hide_unchanged_columns",
            "in": "query",
            "required": false,
            "description": "Whether to hide unchanged columns in the diff. Default is `false`.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "left_spreadsheet",
                  "right_spreadsheet"
                ],
                "properties": {
                  "left_spreadsheet": {
                    "type": "string",
                    "format": "binary",
                    "description": "Left spreadsheet file. File extension must be .xlsx, .xls, or .csv."
                  },
                  "right_spreadsheet": {
                    "type": "string",
                    "format": "binary",
                    "description": "Right spreadsheet file. File extension must be .xlsx, .xls, or .csv."
                  },
                  "left_sheet_name": {
                    "type": "string",
                    "description": "The sheet name from the left spreadsheet to diff. If not provided, the first sheet will be used."
                  },
                  "right_sheet_name": {
                    "type": "string",
                    "description": "The sheet name from the right spreadsheet to diff. If not provided, the first sheet will be used."
                  },
                  "left_header_row": {
                    "type": "integer",
                    "description": "The row number to use as the header from the left spreadsheet. If not provided, the first row will be used."
                  },
                  "right_header_row": {
                    "type": "integer",
                    "description": "The row number to use as the header from the right spreadsheet. If not provided, the first row will be used."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "left_spreadsheet",
                  "right_spreadsheet"
                ],
                "properties": {
                  "left_spreadsheet": {
                    "type": "string",
                    "description": "Data URL of the left spreadsheet (data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,...)."
                  },
                  "right_spreadsheet": {
                    "type": "string",
                    "description": "Data URL of the right spreadsheet."
                  },
                  "left_sheet_name": {
                    "type": "string",
                    "description": "The sheet name from the left spreadsheet to diff. If not provided, the first sheet will be used."
                  },
                  "right_sheet_name": {
                    "type": "string",
                    "description": "The sheet name from the right spreadsheet to diff. If not provided, the first sheet will be used."
                  },
                  "left_header_row": {
                    "type": "integer",
                    "description": "The row number to use as the header from the left spreadsheet. If not provided, the first row will be used."
                  },
                  "right_header_row": {
                    "type": "integer",
                    "description": "The row number to use as the header from the right spreadsheet. If not provided, the first row will be used."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diff computed successfully.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExcelDiffResponse"
                },
                "example": {
                  "creditsUsed": 1,
                  "table": [
                    [
                      [
                        {
                          "value": "Bird",
                          "type": "equal"
                        }
                      ],
                      [
                        {
                          "value": "Population",
                          "type": "equal"
                        }
                      ]
                    ],
                    [
                      [
                        {
                          "value": "Kagu",
                          "type": "equal"
                        }
                      ],
                      [
                        {
                          "value": "1,000",
                          "type": "equal"
                        }
                      ]
                    ],
                    [
                      [
                        {
                          "value": "Dodo",
                          "type": "removed"
                        }
                      ],
                      [
                        {
                          "value": "0",
                          "type": "removed"
                        }
                      ]
                    ],
                    [
                      [
                        {
                          "value": "Kiwi",
                          "type": "equal"
                        }
                      ],
                      [
                        {
                          "value": "120,000",
                          "type": "removed"
                        },
                        {
                          "value": "70,000",
                          "type": "inserted"
                        }
                      ]
                    ]
                  ],
                  "rows": [
                    {
                      "type": "equal",
                      "original": 1,
                      "new": 1
                    },
                    {
                      "type": "equal",
                      "original": 2,
                      "new": 2
                    },
                    {
                      "type": "removed",
                      "original": 3,
                      "new": null
                    },
                    {
                      "type": "modified",
                      "original": 4,
                      "new": 3
                    }
                  ],
                  "columns": [
                    {
                      "type": "equal",
                      "original": 1,
                      "new": 1
                    },
                    {
                      "type": "modified",
                      "original": 2,
                      "new": 2
                    }
                  ],
                  "stats": {
                    "moved": 0,
                    "inserted": 1,
                    "removed": 2,
                    "rows": 4,
                    "columns": 2
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request data or spreadsheet content.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "validation_error": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "VALIDATION_ERROR",
                        "message": "One or more validation errors occurred.",
                        "hint": "Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started",
                        "details": [
                          {
                            "msg": "Invalid value",
                            "param": "input_type",
                            "location": "query"
                          }
                        ]
                      }
                    }
                  },
                  "corrupt_spreadsheet": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_SPREADSHEET",
                        "message": "Could not process spreadsheet. File may be corrupted.",
                        "hint": "Confirm both inputs are valid, uncorrupted .xlsx, .xls or .csv files, then retry.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_json": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_JSON",
                        "message": "The request body contains invalid JSON.",
                        "hint": "Send a syntactically valid JSON body with the Content-Type header set to application/json.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "missing_sheet": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "SHEET_NOT_FOUND",
                        "message": "Left sheet name MissingSheet not found in spreadsheet.",
                        "hint": "Use a sheet name present in the uploaded workbook: Sheet1, Summary.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "invalid_header_row": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 400,
                        "code": "INVALID_HEADER_ROW",
                        "message": "Invalid left header row: -1.",
                        "hint": "Pass a positive integer row number, where 1 is the first row of the sheet.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "408": {
            "description": "Request timed out.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 408,
                    "code": "REQUEST_TIMEOUT",
                    "message": "Request timed out.",
                    "hint": "Retry with smaller spreadsheets, or narrow the comparison with the sheet_name parameters.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "description": "Spreadsheet diff failed due to a server-side processing error, or an unexpected server failure.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/XCreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "processing_failed": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "SPREADSHEET_PROCESSING_FAILED",
                        "message": "Unexpected spreadsheet processing failure.",
                        "hint": "Retry only if creditsUsed is 0. A non-zero creditsUsed (also sent as the X-Credits-Used header) means this comparison was already charged and a retry would bill it again. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  },
                  "unexpected_failure": {
                    "value": {
                      "creditsUsed": 0,
                      "error": {
                        "status": 500,
                        "code": "INTERNAL_SERVER_ERROR",
                        "message": "The server encountered an unexpected error.",
                        "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                        "documentation": "https://www.diffchecker.com/docs/getting-started"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "API key provided to paid subscribers."
      },
      "email": {
        "type": "apiKey",
        "in": "query",
        "name": "email",
        "description": "Your email address for free tier access."
      }
    },
    "parameters": {
      "email": {
        "name": "email",
        "in": "query",
        "required": false,
        "description": "Your email address. Required if not using an API key.",
        "schema": {
          "type": "string",
          "format": "email"
        }
      }
    },
    "headers": {
      "XCreditsUsed": {
        "description": "Credits charged for the request. Present on every public API response. JSON responses also include the same value in the `creditsUsed` body field for backwards compatibility.",
        "schema": {
          "type": "integer",
          "example": 1
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying the request.",
        "schema": {
          "type": "integer",
          "example": 120
        }
      },
      "Allow": {
        "description": "Comma-separated list of methods the endpoint supports. Sent with every 405 response.",
        "schema": {
          "type": "string",
          "example": "POST, OPTIONS"
        }
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "description": "Every error response body carries this object under `error`. The fields\n`status`, `code`, `message`, `hint` and `documentation` are always present, so a\nclient can branch on `code`, surface `message`, act on `hint` and follow\n`documentation` without special-casing an endpoint.\n",
        "properties": {
          "status": {
            "type": "integer",
            "description": "The HTTP status code of the response, repeated here as RFC 9457 describes so a logged `error` object stays self-describing."
          },
          "code": {
            "type": "string",
            "description": "A stable, machine-readable error code."
          },
          "message": {
            "type": "string",
            "description": "A human-readable description of what went wrong."
          },
          "hint": {
            "type": "string",
            "description": "A concrete next step that resolves the error."
          },
          "documentation": {
            "type": "string",
            "format": "uri",
            "description": "Link to the API reference."
          },
          "details": {
            "description": "Structured, error-specific context. Validation errors list the offending\nparameters; other errors may describe the limit that was exceeded.\n",
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              {
                "type": "object"
              }
            ]
          }
        },
        "required": [
          "status",
          "code",
          "message",
          "hint",
          "documentation"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the request. Rejected requests usually report `0`."
          },
          "error": {
            "$ref": "#/components/schemas/ApiError"
          }
        },
        "required": [
          "creditsUsed",
          "error"
        ]
      },
      "RetriableErrorResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the request. Rejected requests usually report `0`."
          },
          "retryAfterSeconds": {
            "type": "integer",
            "description": "Seconds until the request should be retried."
          },
          "error": {
            "$ref": "#/components/schemas/ApiError"
          }
        },
        "required": [
          "creditsUsed",
          "retryAfterSeconds",
          "error"
        ]
      },
      "TextDiffJsonResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the diff request."
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "end": {
                  "type": "boolean"
                },
                "start": {
                  "type": "boolean"
                },
                "insideChanged": {
                  "type": "boolean"
                },
                "left": {
                  "$ref": "#/components/schemas/DiffSide"
                },
                "right": {
                  "$ref": "#/components/schemas/DiffSide"
                }
              }
            }
          },
          "added": {
            "type": "integer",
            "description": "Number of added chunks."
          },
          "removed": {
            "type": "integer",
            "description": "Number of removed chunks."
          }
        },
        "required": [
          "creditsUsed",
          "rows",
          "added",
          "removed"
        ]
      },
      "DiffSide": {
        "type": "object",
        "properties": {
          "chunks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "equal",
                    "insert",
                    "remove"
                  ]
                }
              }
            }
          },
          "line": {
            "type": "integer"
          }
        }
      },
      "HtmlJsonResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the diff request."
          },
          "html": {
            "type": "string",
            "description": "HTML markup of the diff table."
          },
          "css": {
            "type": "string",
            "description": "CSS styles for the diff table."
          }
        },
        "required": [
          "creditsUsed",
          "html",
          "css"
        ]
      },
      "RichTextPoint": {
        "type": "array",
        "description": "A single polygon point in PDF coordinate space as [x, y].",
        "items": {
          "type": "number"
        }
      },
      "RichTextPolygon": {
        "type": "array",
        "description": "Polygon outline made of RichTextPoint items.",
        "items": {
          "$ref": "#/components/schemas/RichTextPoint"
        }
      },
      "RichTextMoveSegments": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "remove",
              "insert"
            ]
          },
          "polygons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RichTextPolygon"
            }
          }
        }
      },
      "RichTextChunk": {
        "type": "object",
        "description": "Represents a single diff chunk. Text chunks include `text`.\nVisual chunks can include `image` metadata. Equal text chunks can expose style flags.\n",
        "properties": {
          "id": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "enum": [
              "equal",
              "insert",
              "remove",
              "move"
            ]
          },
          "pageIndex": {
            "type": "integer"
          },
          "text": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "polygons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RichTextPolygon"
            }
          },
          "moveSegments": {
            "$ref": "#/components/schemas/RichTextMoveSegments"
          },
          "fontFamilyChanged": {
            "type": "boolean"
          },
          "fontSizeChanged": {
            "type": "boolean"
          },
          "colorChanged": {
            "type": "boolean"
          },
          "image": {
            "type": "object",
            "properties": {
              "hash": {
                "type": "string"
              },
              "objectType": {
                "type": "string",
                "enum": [
                  "image",
                  "vector",
                  "form",
                  "shading"
                ]
              },
              "imageUrl": {
                "type": "string",
                "description": "Base64-encoded image data URL."
              },
              "width": {
                "type": "number"
              },
              "height": {
                "type": "number"
              },
              "byteSize": {
                "type": "number"
              },
              "bounds": {
                "type": "object",
                "properties": {
                  "left": {
                    "type": "number"
                  },
                  "top": {
                    "type": "number"
                  },
                  "right": {
                    "type": "number"
                  },
                  "bottom": {
                    "type": "number"
                  }
                }
              }
            }
          }
        },
        "required": [
          "id",
          "type",
          "pageIndex",
          "polygons"
        ]
      },
      "RichTextStyleChange": {
        "type": "object",
        "properties": {
          "chunkId": {
            "type": "integer"
          },
          "text": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "style"
            ]
          },
          "chunkBefore": {
            "$ref": "#/components/schemas/RichTextChunk"
          },
          "chunkAfter": {
            "$ref": "#/components/schemas/RichTextChunk"
          }
        }
      },
      "RichTextChangeLogItem": {
        "type": "object",
        "properties": {
          "chunkId": {
            "type": "integer"
          },
          "contentBefore": {
            "type": "string"
          },
          "contentAfter": {
            "type": "string"
          },
          "contentType": {
            "type": "string",
            "enum": [
              "text",
              "visual"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "insert",
              "remove",
              "replace",
              "move",
              "style"
            ]
          },
          "pageIndex": {
            "type": "integer"
          }
        }
      },
      "RichTextPageDimensions": {
        "type": "object",
        "properties": {
          "width": {
            "type": "number"
          },
          "height": {
            "type": "number"
          }
        },
        "required": [
          "width",
          "height"
        ]
      },
      "RichTextPageInfo": {
        "type": "object",
        "properties": {
          "pageCount": {
            "type": "integer"
          },
          "pageDimensions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RichTextPageDimensions"
            }
          },
          "rotations": {
            "type": "array",
            "description": "Per-page /Rotate as PDFium quarter turns. 0=0°, 1=90°, 2=180°, 3=270°.",
            "items": {
              "type": "integer",
              "enum": [
                0,
                1,
                2,
                3
              ]
            }
          },
          "pageImages": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Page image data URL."
            }
          },
          "pageImageScale": {
            "type": "number"
          }
        },
        "required": [
          "pageCount",
          "pageDimensions",
          "rotations",
          "pageImageScale"
        ]
      },
      "RichTextDiffPayload": {
        "type": "object",
        "properties": {
          "left": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RichTextChunk"
            }
          },
          "right": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RichTextChunk"
            }
          },
          "changeLog": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/RichTextChangeLogItem"
                },
                {
                  "$ref": "#/components/schemas/RichTextStyleChange"
                }
              ]
            }
          }
        },
        "required": [
          "left",
          "right",
          "changeLog"
        ]
      },
      "RichTextJsonResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the diff request."
          },
          "diff": {
            "$ref": "#/components/schemas/RichTextDiffPayload"
          },
          "left": {
            "$ref": "#/components/schemas/RichTextPageInfo"
          },
          "right": {
            "$ref": "#/components/schemas/RichTextPageInfo"
          }
        },
        "required": [
          "creditsUsed",
          "diff",
          "left",
          "right"
        ]
      },
      "ImageDiffJsonResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the diff request."
          },
          "dataUrl": {
            "type": "string",
            "description": "Data URL of the diff image (PNG)."
          },
          "diffPixels": {
            "type": "integer",
            "description": "Number of pixels that differ."
          },
          "totalPixels": {
            "type": "integer",
            "description": "Total number of pixels compared."
          },
          "misMatchPercentage": {
            "type": "number",
            "format": "float",
            "description": "Percentage of pixels that differ."
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "originalWidth": {
            "type": "integer"
          },
          "originalHeight": {
            "type": "integer"
          },
          "changedWidth": {
            "type": "integer"
          },
          "changedHeight": {
            "type": "integer"
          }
        },
        "required": [
          "creditsUsed",
          "dataUrl",
          "diffPixels",
          "totalPixels",
          "misMatchPercentage",
          "width",
          "height",
          "originalWidth",
          "originalHeight",
          "changedWidth",
          "changedHeight"
        ]
      },
      "ExcelDiffResponse": {
        "type": "object",
        "properties": {
          "creditsUsed": {
            "type": "integer",
            "description": "Credits charged for the diff request."
          },
          "table": {
            "type": "array",
            "description": "The diff results for each cell. Cells are organized by rows, with each row containing cells in column order (left to right). Each cell is represented by an array of one or two objects. If the cell value changed, there will be two objects (one removed, one inserted). Each object contains the `type` of change and the `value`.\n",
            "items": {
              "type": "array",
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "value": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "equal",
                        "removed",
                        "inserted"
                      ]
                    }
                  }
                }
              }
            }
          },
          "rows": {
            "type": "array",
            "description": "Row-level diff metadata. Each entry contains the original row number, the new row number, and the type of change.\n",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "equal",
                    "removed",
                    "inserted",
                    "modified"
                  ]
                },
                "original": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "new": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          },
          "columns": {
            "type": "array",
            "description": "Column-level diff metadata. Each entry contains the original column number, the new column number, and the type of change.\n",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "equal",
                    "removed",
                    "inserted",
                    "modified"
                  ]
                },
                "original": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "new": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          },
          "stats": {
            "type": "object",
            "description": "Summary statistics for the diff.",
            "properties": {
              "moved": {
                "type": "integer"
              },
              "inserted": {
                "type": "integer"
              },
              "removed": {
                "type": "integer"
              },
              "rows": {
                "type": "integer",
                "description": "Total rows in the output."
              },
              "columns": {
                "type": "integer",
                "description": "Total columns in the output."
              }
            }
          }
        },
        "required": [
          "creditsUsed",
          "table",
          "rows",
          "columns",
          "stats"
        ]
      }
    },
    "responses": {
      "ValidationError": {
        "description": "One or more validation errors occurred, or the JSON body could not be parsed.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "validation_error": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 400,
                    "code": "VALIDATION_ERROR",
                    "message": "One or more validation errors occurred.",
                    "hint": "Each entry in `details` names the offending parameter and its location. Correct those parameters and retry.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started",
                    "details": [
                      {
                        "msg": "Invalid value",
                        "param": "output_type",
                        "location": "query"
                      }
                    ]
                  }
                }
              },
              "invalid_json": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 400,
                    "code": "INVALID_JSON",
                    "message": "The request body contains invalid JSON.",
                    "hint": "Send a syntactically valid JSON body with the Content-Type header set to application/json.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication failed. Provide a valid email or API key. Depending on the failure, the response can include more specific error codes.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "unauthorized": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 401,
                    "code": "UNAUTHORIZED",
                    "message": "In order to use the API, please provide an API key via the \"X-Api-Key\" header or email via the \"email\" key in the query string.",
                    "hint": "Send the \"X-Api-Key\" header, or add \"?email=you@example.com\" to the request URL for free-tier access.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "invalid_email": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 401,
                    "code": "INVALID_EMAIL",
                    "message": "In order to use the free API, please provide a valid email via the \"email\" key in the query string.",
                    "hint": "Add \"?email=you@example.com\" to the request URL, or authenticate with an API key instead.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "no_default_email": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 401,
                    "code": "NO_DEFAULT_EMAIL",
                    "message": "Please change the email in your request from test@test.com to your own email.",
                    "hint": "Replace the placeholder with your own address in the \"email\" query parameter.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "invalid_api_key": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 401,
                    "code": "API_KEY_INVALID",
                    "message": "Please provide a valid API key.",
                    "hint": "Send the key from https://www.diffchecker.com/account in the \"X-Api-Key\" header.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "subscription_expired": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 401,
                    "code": "SUBSCRIPTION_EXPIRED",
                    "message": "Subscription has expired. Please renew your subscription or upgrade to a higher plan.",
                    "hint": "Renew or upgrade the subscription at https://www.diffchecker.com/account, then retry with the same API key.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Depending on the throttle, the response may also include `retryAfterSeconds` and a `Retry-After` response header.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RetriableErrorResponse"
                }
              ]
            },
            "examples": {
              "free_diff_limit": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 429,
                    "code": "FREE_DIFF_LIMIT_EXCEEDED",
                    "message": "Free request limit exceeded - please wait until the end of the month or upgrade to a paid plan.",
                    "hint": "Wait until the free quota resets at the start of next month, or buy a plan at https://www.diffchecker.com/buy-public-api.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "paid_diff_limit": {
                "value": {
                  "creditsUsed": 0,
                  "error": {
                    "status": 429,
                    "code": "PAID_DIFF_LIMIT_EXCEEDED",
                    "message": "Credit limit exceeded - please wait until the end of the billing period or upgrade your plan.",
                    "hint": "Wait for the billing period to reset, or upgrade the plan at https://www.diffchecker.com/account.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "failed_request_limit": {
                "value": {
                  "creditsUsed": 0,
                  "retryAfterSeconds": 120,
                  "error": {
                    "status": 429,
                    "code": "FAILED_REQUEST_LIMIT_EXCEEDED",
                    "message": "Too many failed API requests that used 0 credits. Please wait a few minutes and try again.",
                    "hint": "Wait for the number of seconds in the \"Retry-After\" header, then retry with a corrected request.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              },
              "failed_request_daily_limit": {
                "value": {
                  "creditsUsed": 0,
                  "retryAfterSeconds": 3600,
                  "error": {
                    "status": 429,
                    "code": "FAILED_REQUEST_DAILY_LIMIT_EXCEEDED",
                    "message": "Too many failed API requests that used 0 credits in the last 24 hours. Please try again later.",
                    "hint": "Wait for the number of seconds in the \"Retry-After\" header, then retry with a corrected request.",
                    "documentation": "https://www.diffchecker.com/docs/getting-started"
                  }
                }
              }
            }
          }
        }
      },
      "RequestTooLarge": {
        "description": "The request exceeded the active size limit for the caller's authentication method or plan.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "creditsUsed": 0,
              "error": {
                "status": 413,
                "code": "LIMIT_FILE_SIZE",
                "message": "Request too large! Max allowed size is 5 MB",
                "hint": "Send inputs totalling at most 5 MB, or upgrade to a plan with a higher size limit.",
                "documentation": "https://www.diffchecker.com/docs/getting-started"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "No endpoint matches the request path.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "creditsUsed": 0,
              "error": {
                "status": 404,
                "code": "NOT_FOUND",
                "message": "No route matches POST /public/txt.",
                "hint": "Check the method and path against the endpoint reference. Every public API endpoint lives under the /public prefix.",
                "documentation": "https://www.diffchecker.com/docs/getting-started"
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The endpoint exists but does not support the request method. The `Allow` response header lists the methods it does support.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          },
          "Allow": {
            "$ref": "#/components/headers/Allow"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "creditsUsed": 0,
              "error": {
                "status": 405,
                "code": "METHOD_NOT_ALLOWED",
                "message": "GET is not supported on /public/text.",
                "hint": "Retry the request with POST.",
                "documentation": "https://www.diffchecker.com/docs/getting-started"
              }
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "The request Content-Type is not one this endpoint accepts. `/text` accepts only application/json; the upload endpoints accept application/json and multipart/form-data.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "creditsUsed": 0,
              "error": {
                "status": 415,
                "code": "UNSUPPORTED_MEDIA_TYPE",
                "message": "Content-Type \"text/plain\" is not supported on this endpoint.",
                "hint": "Send the body as application/json or multipart/form-data.",
                "documentation": "https://www.diffchecker.com/docs/getting-started"
              }
            }
          }
        }
      },
      "InternalServerError": {
        "description": "The server hit an unexpected failure while handling the request. A failure after the diff was recorded can still incur charges. Check creditsUsed and X-Credits-Used to determine whether credits were charged before retrying.",
        "headers": {
          "X-Credits-Used": {
            "$ref": "#/components/headers/XCreditsUsed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "creditsUsed": 0,
              "error": {
                "status": 500,
                "code": "INTERNAL_SERVER_ERROR",
                "message": "The server encountered an unexpected error.",
                "hint": "Retry the request. If it keeps failing, contact support@diffchecker.com with the time of the request.",
                "documentation": "https://www.diffchecker.com/docs/getting-started"
              }
            }
          }
        }
      }
    }
  }
}
