Clean.tools Text API

Text analysis and transformation — deterministic.

Operations 8

POST /v1/diff_text Use this when you need an exact line-level diff between two blocks of text… #
POST /v1/count_text Use this when you need exact word, character, sentence, and paragraph counts… #
POST /v1/convert_case Use this when you need to re-case text into a specific naming or letter case #
POST /v1/fancy_text Use this when you need to style ASCII letters and digits as Unicode glyphs… #
POST /v1/render_markdown Use this when you need to convert lightweight Markdown into a sanitized… #
POST /v1/lorem_ipsum Use this when you need placeholder/filler copy for mockups, tests, or layout #
POST /v1/redact_text Use this when scrubbing test/dev text: replaces each occurrence of the given… #
POST /v1/slugify Use this when you need a URL- or filename-safe slug from arbitrary text #

Work with this as data

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

MCP server

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

https://apis.io/mcp

Tools for apis

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

Call it yourself

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

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

Get an API key

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

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

OpenAPI Specification

clean-tools-text-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Clean.tools Text API
  version: 0.1.0
  summary: Read-only developer, finance, date, and text utilities. No key, no signup.
  description: 'Every endpoint is read-only and side-effect-free. Most tools are deterministic: same input, same output. The generator tools (uuid_v4, generate_id, random_number, generate_password) use cryptographic randomness instead. Requests are processed in memory and never written to storage or logs; only anonymous per-tool call counters are kept. The same tools are available over the Model Context Protocol at POST /mcp (mount a subset with ?tools=). Rate limit: about 60 requests/minute per caller — honor Retry-After on 429 and add jitter.'
  license:
    name: MIT
  contact:
    name: Clean.tools
    url: https://clean.tools/
    email: support@clean.tools
servers:
- url: https://api.clean.tools
tags:
- name: Text
  description: Text analysis and transformation — deterministic.
paths:
  /v1/diff_text:
    post:
      operationId: diff_text
      summary: Use this when you need an exact line-level diff between two blocks of text…
      description: 'Use this when you need an exact line-level diff between two blocks of text instead of eyeballing the differences. Deterministic: same input, same output. Computes a longest-common-subsequence diff and returns every line tagged added, removed, or unchanged, plus per-category counts. Example: original "a\nb", modified "a\nB" -> added 1, removed 1, unchanged 1, with lines [{type:"unchanged",text:"a"},{type:"removed",text:"b"},{type:"added",text:"B"}]. Trailing edits produce separate removed+added lines rather than an in-place change. Inputs whose line-count product exceeds 4,000,000 are rejected as too large to diff.'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                original:
                  type: string
                  description: Original text.
                modified:
                  type: string
                  description: Modified text.
              required:
              - original
              - modified
            example:
              original: 'a

                b'
              modified: 'a

                B'
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    additionalProperties: false
                    required:
                    - added
                    - removed
                    - unchanged
                    - lines
                    properties:
                      added:
                        type: integer
                        description: Number of lines present only in the modified text.
                      removed:
                        type: integer
                        description: Number of lines present only in the original text.
                      unchanged:
                        type: integer
                        description: Number of lines common to both texts.
                      lines:
                        type: array
                        description: The full diff in order, one entry per line.
                        items:
                          type: object
                          additionalProperties: false
                          required:
                          - type
                          - text
                          properties:
                            type:
                              type: string
                              enum:
                              - added
                              - removed
                              - unchanged
                              description: How this line differs between the two texts.
                            text:
                              type: string
                              description: The line content (without its trailing newline).
              example:
                tool: diff_text
                result:
                  added: 1
                  removed: 1
                  unchanged: 1
                  lines:
                  - type: unchanged
                    text: a
                  - type: removed
                    text: b
                  - type: added
                    text: B
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/count_text:
    post:
      operationId: count_text
      summary: Use this when you need exact word, character, sentence, and paragraph counts…
      description: 'Use this when you need exact word, character, sentence, and paragraph counts instead of estimating. Deterministic: same input, same output. Uses Unicode-aware segmentation (Intl.Segmenter): characters are grapheme clusters, so an emoji or an accented letter counts as one; words are word-like segments; sentence splitting is abbreviation-aware (Dr., etc., won''t end a sentence). charactersNoSpaces counts graphemes after stripping whitespace, and paragraphs are blocks separated by blank lines. Example: "Café 👩‍💻!" -> words 1, characters 7, charactersNoSpaces 6, sentences 1, paragraphs 1. Empty input returns all zeros.'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                text:
                  type: string
                  description: Text to analyze.
              required:
              - text
            example:
              text: Café 👩‍💻!
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    additionalProperties: false
                    required:
                    - words
                    - characters
                    - charactersNoSpaces
                    - sentences
                    - paragraphs
                    properties:
                      words:
                        type: integer
                        description: Count of word-like segments.
                      characters:
                        type: integer
                        description: Count of grapheme clusters (user-perceived characters), including whitespace.
                      charactersNoSpaces:
                        type: integer
                        description: Grapheme count after removing all whitespace.
                      sentences:
                        type: integer
                        description: Sentence count using abbreviation-aware segmentation.
                      paragraphs:
                        type: integer
                        description: Count of non-empty blocks separated by blank lines.
              example:
                tool: count_text
                result:
                  words: 1
                  characters: 7
                  charactersNoSpaces: 6
                  sentences: 1
                  paragraphs: 1
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/convert_case:
    post:
      operationId: convert_case
      summary: Use this when you need to re-case text into a specific naming or letter case
      description: 'Use this when you need to re-case text into a specific naming or letter case. Given `text` and a target `case` (upper, lower, title, sentence, camel, snake, kebab, or constant), returns the converted string. Smart word tokenization splits camelCase, snake_case, kebab-case, and whitespace, so a phrase in any style re-cases consistently; title case honors an editorial stop-word list and preserves ALL-CAPS acronyms. Empty text returns an empty result. Deterministic: same input, same output. Example: {text: "myVariableName", case: "constant"} -> result "MY_VARIABLE_NAME".'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                text:
                  type: string
                  description: The input text to convert.
                case:
                  type: string
                  enum:
                  - upper
                  - lower
                  - title
                  - sentence
                  - camel
                  - snake
                  - kebab
                  - constant
                  description: 'Target case: upper (UPPER CASE), lower (lower case), title (Title Case with stop-words), sentence (Sentence case), camel (camelCase), snake (snake_case), kebab (kebab-case), constant (CONSTANT_CASE).'
              required:
              - text
              - case
            example:
              text: myVariableName
              case: constant
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    properties:
                      case:
                        type: string
                        description: The target case that was applied (echoes the requested `case`).
                      result:
                        type: string
                        description: The converted text. Empty string if the input text was empty.
                    required:
                    - case
                    - result
                    additionalProperties: false
              example:
                tool: convert_case
                result:
                  case: constant
                  result: MY_VARIABLE_NAME
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/fancy_text:
    post:
      operationId: fancy_text
      summary: Use this when you need to style ASCII letters and digits as Unicode glyphs…
      description: 'Use this when you need to style ASCII letters and digits as Unicode glyphs (bold-serif, italic-serif, bold-italic-serif, bold-sans, script, fraktur, double-struck, monospace, circled, squared, parenthesized, small-caps) for places that lack font control such as social bios or usernames. Pass a `style` and `text` to get the transformed string; characters outside A-Z, a-z, and 0-9 (spaces, punctuation, emoji) pass through unchanged. Omit `style` to receive the list of valid style keys instead of transforming. Deterministic: same input, same output. Example: {style: "bold-serif", text: "Hello 123"} -> result "𝐇𝐞𝐥𝐥𝐨 𝟏𝟐𝟑".'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                text:
                  type: string
                  description: The text to transform. ASCII A-Z, a-z, and 0-9 are mapped to styled glyphs; other characters (spaces, punctuation, emoji) pass through unchanged. Required when a style is given.
                style:
                  type: string
                  enum:
                  - bold-serif
                  - italic-serif
                  - bold-italic-serif
                  - bold-sans
                  - script
                  - fraktur
                  - double-struck
                  - monospace
                  - circled
                  - squared
                  - parenthesized
                  - small-caps
                  description: The style to apply. Omit entirely to receive the list of valid style keys instead of transforming.
              required: []
            example:
              style: bold-serif
              text: Hello 123
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    properties:
                      style:
                        type: string
                        description: 'Transform mode only: the style that was applied (echoes the requested `style`).'
                      result:
                        type: string
                        description: 'Transform mode only: the styled text, with unsupported characters passed through unchanged.'
                      styles:
                        type: array
                        items:
                          type: string
                        description: 'Discovery mode only (when `style` is omitted): the list of valid style keys.'
              example:
                tool: fancy_text
                result:
                  style: bold-serif
                  result: 𝐇𝐞𝐥𝐥𝐨 𝟏𝟐𝟑
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/render_markdown:
    post:
      operationId: render_markdown
      summary: Use this when you need to convert lightweight Markdown into a sanitized…
      description: 'Use this when you need to convert lightweight Markdown into a sanitized, XSS-safe HTML fragment to preview or embed, matching the Clean.tools markdown preview. Deterministic: same input, same output. Supports headings, bold/italic/strikethrough, inline and fenced code, links and images (http/https/mailto URL schemes only; other schemes become "#"), blockquotes, ordered/unordered/task lists, GFM tables, and horizontal rules. All raw angle brackets are HTML-escaped so the output is safe to inject. Example: "# Hi\n\n**bold**" -> html "

        Hi


        bold

        ".'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                markdown:
                  type: string
                  description: The Markdown source text to render to HTML.
              required:
              - markdown
            example:
              markdown: '# Hi


                **bold**'
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    properties:
                      html:
                        type: string
                        description: The rendered HTML fragment. Block elements are concatenated with no separators; inline styles are attached to tables, code, blockquotes, images, and task-list items. No wrapping document element.
                    required:
                    - html
                    additionalProperties: false
              example:
                tool: render_markdown
                result:
                  html: <h1>Hi</h1><p><strong>bold</strong></p>
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/lorem_ipsum:
    post:
      operationId: lorem_ipsum
      summary: Use this when you need placeholder/filler copy for mockups, tests, or layout
      description: 'Use this when you need placeholder/filler copy for mockups, tests, or layout. Given a `mode` ("paragraphs", "sentences", "words", or "formatted") and a `count`, cycles a fixed built-in Latin corpus to return the same text every time. `count` is clamped to the mode''s max (paragraphs 20, sentences 100, words 500) and defaults to 1 when missing or below 1; "formatted" ignores `count` and returns a fixed multi-block sample (with count 0). Deterministic: same input, same output. Example: {mode: "words", count: 5} -> text "Lorem ipsum dolor sit amet.", count 5.'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                mode:
                  type: string
                  enum:
                  - paragraphs
                  - sentences
                  - words
                  - formatted
                  description: Unit of generated text. "paragraphs", "sentences", or "words" repeat the corpus up to the requested count; "formatted" returns a fixed multi-block sample as plain text and ignores count.
                count:
                  type: integer
                  minimum: 1
                  description: How many units to generate. Clamped to the mode's max (paragraphs 20, sentences 100, words 500); values below 1 or missing default to 1. Unused for "formatted".
              required:
              - mode
            example:
              mode: words
              count: 5
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    properties:
                      mode:
                        type: string
                        description: The generation mode used (echoes the requested `mode`).
                        enum:
                        - paragraphs
                        - sentences
                        - words
                        - formatted
                      count:
                        type: integer
                        description: The effective number of units generated after clamping/defaulting; always 0 for "formatted" mode.
                      text:
                        type: string
                        description: The generated placeholder text. Paragraphs are separated by blank lines; words mode is capitalized and terminated with a period.
                    required:
                    - mode
                    - count
                    - text
                    additionalProperties: false
              example:
                tool: lorem_ipsum
                result:
                  mode: words
                  count: 5
                  text: Lorem ipsum dolor sit amet.
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/redact_text:
    post:
      operationId: redact_text
      summary: 'Use this when scrubbing test/dev text: replaces each occurrence of the given…'
      description: 'Use this when scrubbing test/dev text: replaces each occurrence of the given terms with block characters (████). Provide `text` plus `terms` (a comma-separated string or an array of strings). By default it matches whole words only using Unicode boundaries (so "ann" will not match inside "annual") and is case-insensitive; set `caseSensitive` to match exactly, `wholeWords: false` to match substrings, or `fixedWidth: true` to hide each term''s length behind a constant-width bar. Returns the redacted text and a replacement count, and never echoes the original terms. Deterministic: same input, same output. Truly sensitive text is better redacted client-side at clean.tools/text-redact/. Example: {text: "Contact Jane Doe", terms: "Jane Doe"} -> redacted "Contact ████████", redactedCount 1.'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                text:
                  type: string
                  description: The text to redact terms from.
                terms:
                  description: The sensitive terms to redact, given either as a comma-separated string (e.g. "Jane Doe, jane@x.com") or an array of strings.
                  oneOf:
                  - type: string
                  - type: array
                    items:
                      type: string
                wholeWords:
                  type: boolean
                  description: When true (default), only match terms as whole words using Unicode word boundaries (so "ann" will not match inside "annual").
                caseSensitive:
                  type: boolean
                  description: When true, match terms case-sensitively. Defaults to false (case-insensitive).
                fixedWidth:
                  type: boolean
                  description: When true, replace every matched term with a constant-width block bar so the redacted length does not leak the original term length. Defaults to false (block length equals term length).
              required:
              - text
              - terms
            example:
              text: Contact Jane Doe
              terms: Jane Doe
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    properties:
                      redacted:
                        type: string
                        description: The text with all matched terms replaced by block characters; identical to the input when no terms matched.
                      redactedCount:
                        type: integer
                        description: The number of replacements made.
                    required:
                    - redacted
                    - redactedCount
                    additionalProperties: false
              example:
                tool: redact_text
                result:
                  redacted: Contact ████████
                  redactedCount: 1
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
  /v1/slugify:
    post:
      operationId: slugify
      summary: Use this when you need a URL- or filename-safe slug from arbitrary text
      description: 'Use this when you need a URL- or filename-safe slug from arbitrary text. Deterministic: same input, same output. Applies Unicode NFKD normalization, strips combining accents, and transliterates non-decomposing letters (ß->ss, æ->ae, œ->oe, ø->o, đ->d, ł->l, þ->th, ð->d, plus uppercase variants), then collapses every run of non-alphanumeric characters to a single separator and trims separators; e.g. "Héllo Wörld!" -> "hello-world". Emoji, CJK, and any other characters with no ASCII form are dropped. Prefer this over transliterating Unicode yourself, which models routinely get wrong. Returns { error } when no URL-safe characters remain.'
      x-read-only: true
      tags:
      - Text
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                text:
                  type: string
                  description: Text to slugify (max 10000 characters).
                separator:
                  type: string
                  maxLength: 1
                  description: 'Word separator: empty string (join words) or a single character from "-", "_", ".". Default "-".'
                lowercase:
                  type: boolean
                  description: Lowercase the result (default true).
                maxLength:
                  type: integer
                  minimum: 0
                  description: Maximum slug length; 0 means no limit (default). When set and exceeded, the slug is cut at a separator boundary when possible, otherwise hard-cut.
              required:
              - text
            example:
              text: Héllo Wörld!
      responses:
        '200':
          description: Structured tool result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tool:
                    type: string
                  result:
                    type: object
                    additionalProperties: false
                    required:
                    - slug
                    - changed
                    properties:
                      slug:
                        type: string
                        description: The URL/filename-safe slug.
                      changed:
                        type: boolean
                        description: True when the slug differs from the input text.
              example:
                tool: slugify
                result:
                  slug: hello-world
                  changed: true
        '400':
          description: Invalid input or the tool reported an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - error
                properties:
                  error:
                    type: string
                    description: Human-readable, structured error message.
                  code:
                    type: string
                    description: Stable machine-readable error code.
                  tool:
                    type: string
                    description: Tool name, when the error is tool-specific.
        '413':
          description: Request body exceeds the 128 KB limit.
        '429':
          description: Rate limit exceeded; the response carries Retry-After and RateLimit-* headers — honor them and add jitter.
externalDocs:
  description: LLM guide
  url: https://api.clean.tools/llms.txt