{
  "openapi": "3.1.0",
  "info": {
    "title": "UtilsForAgents API",
    "description": "High-speed utility microservices for AI agents \u2014 JSON diff, image EXIF/scrub, HTML-to-Markdown, text extraction, URL metadata. All /v1/* endpoints are gated by the x402 payment protocol (HTTP 402 + USDC on Base).",
    "version": "2.0.0",
    "contact": {
      "name": "UtilsForAgents",
      "url": "https://utilsforagents.com"
    },
    "license": {
      "name": "Proprietary"
    },
    "x-guidance": "UtilsForAgents provides seven utility endpoints designed for AI agents. Every /v1/* call costs $0.003 USD, paid inline via the x402 v2 payment protocol \u2014 no API keys or accounts needed.\n\nPayment flow:\n1. POST JSON (or binary for image endpoints) to any /v1/* path.\n2. The server replies HTTP 402 with a `PAYMENT-REQUIRED` header (base64-encoded JSON containing `accepts` array of PaymentRequirements).\n3. Build an EIP-3009 TransferWithAuthorization signature for USDC on Base (eip155:8453).\n4. Retry the identical request with a `PAYMENT-SIGNATURE` header (base64-encoded payment payload).\n5. On valid payment the server returns the normal 200 result with a `PAYMENT-RESPONSE` header containing settlement details.\n\nEndpoints at a glance:\n\u2022 POST /v1/diff \u2014 structural JSON diff (RFC 6902 ops, RFC 6901 pointers). Send {\"left\": ..., \"right\": ...}.\n\u2022 POST /v1/image/exif-summary \u2014 EXIF extraction from JPEG. Send raw image/jpeg binary body.\n\u2022 POST /v1/image/scrub-metadata \u2014 strip EXIF/XMP/IPTC from JPEG or PNG. Send raw binary body, returns cleaned image.\n\u2022 POST /v1/html/to-markdown \u2014 convert an HTML string to Markdown. Send {\"html\": \"...\"}.\n\u2022 POST /v1/html/fetch-markdown \u2014 fetch a URL, convert its HTML to Markdown. Send {\"url\": \"...\"}.\n\u2022 POST /v1/text/fetch-content \u2014 fetch a URL, auto-detect format, return Markdown/text. Send {\"url\": \"...\"}.\n\u2022 POST /v1/url/metadata \u2014 fetch a URL, extract Open Graph / Twitter Card / meta tags. Send {\"url\": \"...\"}.\n\nGET /health is free and unauthenticated.\n\nAll JSON endpoints accept Content-Type: application/json. Image endpoints accept image/jpeg or image/png. Max upload: 5 MB. Remote-fetch endpoints limit downloaded content to 2 MB and time out after 5 s."
  },
  "servers": [
    {
      "url": "https://utilsforagents.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check",
        "description": "Returns service status. Not gated by payment.",
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "service": {
                      "type": "string",
                      "example": "utilsforagents"
                    },
                    "version": {
                      "type": "string",
                      "example": "1.5.0"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/diff": {
      "post": {
        "operationId": "jsonDiff",
        "summary": "JSON structural diff",
        "description": "Computes a structural diff between two JSON values. Returns RFC 6902-style patch operations with statistics.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DiffRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diff computed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DiffResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/InvalidSchema"
          }
        }
      }
    },
    "/v1/image/exif-summary": {
      "post": {
        "operationId": "exifSummary",
        "summary": "Extract EXIF data from JPEG",
        "description": "Parses EXIF metadata from a JPEG image uploaded as a raw binary body. Returns structured EXIF fields.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "EXIF data extracted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "processingTimeMs": {
                      "type": "number"
                    },
                    "exif": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          }
        }
      }
    },
    "/v1/image/scrub-metadata": {
      "post": {
        "operationId": "scrubMetadata",
        "summary": "Strip metadata from image",
        "description": "Removes all metadata (EXIF, XMP, IPTC) from JPEG or PNG images. Returns the scrubbed image as binary.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scrubbed image",
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          }
        }
      }
    },
    "/v1/html/to-markdown": {
      "post": {
        "operationId": "htmlToMarkdown",
        "summary": "Convert HTML to Markdown",
        "description": "Converts an HTML string to clean Markdown. Accepts JSON body with an 'html' field or raw HTML body.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "html"
                ],
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "HTML string to convert"
                  }
                }
              }
            },
            "text/html": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Markdown conversion result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/InvalidSchema"
          }
        }
      }
    },
    "/v1/html/fetch-markdown": {
      "post": {
        "operationId": "fetchMarkdown",
        "summary": "Fetch URL and convert to Markdown",
        "description": "Fetches a URL, extracts the HTML, and converts it to Markdown.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UrlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fetched and converted to Markdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FetchMarkdownResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/InvalidSchema"
          }
        }
      }
    },
    "/v1/text/fetch-content": {
      "post": {
        "operationId": "fetchContent",
        "summary": "Fetch and extract text content",
        "description": "Fetches a URL and auto-detects the format (HTML, JSON, Markdown, text). HTML is converted to Markdown, JSON is flattened to text, and other formats are returned as-is.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UrlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Content extracted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FetchContentResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/InvalidSchema"
          }
        }
      }
    },
    "/v1/url/metadata": {
      "post": {
        "operationId": "urlMetadata",
        "summary": "Extract URL metadata",
        "description": "Fetches a URL and extracts structured metadata: title, description, Open Graph, Twitter Card, canonical URL, language, and more.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.003"
          },
          "protocols": [
            {
              "x402": {
                "version": 2,
                "network": "eip155:8453"
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UrlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Metadata extracted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UrlMetadataResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/x402Response"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/InvalidSchema"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "DiffRequest": {
        "type": "object",
        "required": [
          "left",
          "right"
        ],
        "properties": {
          "left": {
            "description": "Left-hand JSON value to compare"
          },
          "right": {
            "description": "Right-hand JSON value to compare"
          },
          "options": {
            "type": "object",
            "properties": {
              "includeUnchanged": {
                "type": "boolean",
                "default": false,
                "description": "Count unchanged fields in stats"
              },
              "maxDepth": {
                "type": "integer",
                "minimum": 1,
                "maximum": 256,
                "default": 64,
                "description": "Maximum recursion depth"
              }
            }
          }
        }
      },
      "DiffResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "stats": {
            "type": "object",
            "properties": {
              "added": {
                "type": "integer"
              },
              "removed": {
                "type": "integer"
              },
              "changed": {
                "type": "integer"
              },
              "unchanged": {
                "type": "integer"
              },
              "processingTimeMs": {
                "type": "number"
              }
            }
          },
          "diff": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "op": {
                  "type": "string",
                  "enum": [
                    "add",
                    "remove",
                    "replace"
                  ]
                },
                "path": {
                  "type": "string",
                  "description": "JSON Pointer (RFC 6901)"
                },
                "value": {},
                "oldValue": {},
                "newValue": {}
              }
            }
          }
        }
      },
      "UrlRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL to fetch"
          }
        }
      },
      "MarkdownResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "processingTimeMs": {
            "type": "number"
          },
          "charsBefore": {
            "type": "integer"
          },
          "charsAfter": {
            "type": "integer"
          },
          "markdown": {
            "type": "string"
          }
        }
      },
      "FetchMarkdownResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "processingTimeMs": {
            "type": "number"
          },
          "sourceUrl": {
            "type": "string",
            "format": "uri"
          },
          "charsBefore": {
            "type": "integer"
          },
          "charsAfter": {
            "type": "integer"
          },
          "markdown": {
            "type": "string"
          }
        }
      },
      "FetchContentResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "processingTimeMs": {
            "type": "number"
          },
          "sourceUrl": {
            "type": "string",
            "format": "uri"
          },
          "detectedFormat": {
            "type": "string",
            "enum": [
              "html",
              "json",
              "markdown",
              "text"
            ]
          },
          "charsBefore": {
            "type": "integer"
          },
          "charsAfter": {
            "type": "integer"
          },
          "markdown": {
            "type": "string"
          }
        }
      },
      "UrlMetadataResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "processingTimeMs": {
            "type": "number"
          },
          "sourceUrl": {
            "type": "string",
            "format": "uri"
          },
          "metadata": {
            "type": "object",
            "description": "Extracted page metadata including title, description, Open Graph, Twitter Card, canonical URL, language, etc.",
            "properties": {
              "title": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "canonical": {
                "type": "string",
                "format": "uri"
              },
              "language": {
                "type": "string"
              },
              "openGraph": {
                "type": "object",
                "additionalProperties": true
              },
              "twitterCard": {
                "type": "object",
                "additionalProperties": true
              }
            },
            "additionalProperties": true
          }
        }
      },
      "ProblemDetail": {
        "type": "object",
        "description": "RFC 9457 Problem Details",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "x402Response": {
        "type": "object",
        "description": "x402 v2 Payment Required response. Payment requirements are also sent in the PAYMENT-REQUIRED header (base64-encoded).",
        "required": [
          "x402Version",
          "accepts"
        ],
        "properties": {
          "x402Version": {
            "type": "integer",
            "enum": [
              2
            ]
          },
          "error": {
            "type": "string"
          },
          "resource": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "description": {
                "type": "string"
              },
              "mimeType": {
                "type": "string"
              }
            }
          },
          "accepts": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "scheme",
                "network",
                "amount",
                "payTo",
                "maxTimeoutSeconds",
                "asset"
              ],
              "properties": {
                "scheme": {
                  "type": "string",
                  "enum": [
                    "exact"
                  ]
                },
                "network": {
                  "type": "string",
                  "example": "eip155:8453",
                  "description": "CAIP-2 network identifier"
                },
                "amount": {
                  "type": "string",
                  "example": "3000",
                  "description": "Amount in atomic units (USDC has 6 decimals, so 3000 = $0.003)"
                },
                "asset": {
                  "type": "string",
                  "description": "Token contract address (USDC on Base)"
                },
                "payTo": {
                  "type": "string",
                  "pattern": "^0x[0-9a-fA-F]{40}$"
                },
                "maxTimeoutSeconds": {
                  "type": "integer"
                },
                "extra": {
                  "type": "object",
                  "description": "EIP-712 domain info and resource URL"
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            }
          }
        }
      },
      "InvalidSchema": {
        "description": "Invalid request schema",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Upload exceeds 5 MB limit",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            }
          }
        }
      },
      "UnsupportedMedia": {
        "description": "Unsupported media type",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetail"
            }
          }
        }
      }
    }
  }
}
