{
  "openapi": "3.1.0",
  "info": {
    "title": "Hatchloop Agent Utils — Utility API for AI Agents",
    "version": "1.0.0",
    "description": "Zero-authentication utility API hub optimized for AI agent tool-use. Provides essential primitives that agents need constantly: UUID generation, cryptographic hashing, Base64 encoding/decoding, timestamp retrieval, email/JSON validation, unit conversion, regex testing, cron expression parsing, and JWT decoding. All responses use a consistent JSON envelope: {success, tool, result, timestamp}. No API key required. CORS enabled for all origins.",
    "contact": {
      "name": "Hatchloop AAID",
      "url": "https://hatchloop.dev",
      "email": "hello@hatchloop.dev"
    },
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    }
  },
  "servers": [
    {
      "url": "https://hatchloop.dev",
      "description": "Production server"
    },
    {
      "url": "http://localhost:3847",
      "description": "Local development server"
    }
  ],
  "tags": [
    {
      "name": "identity",
      "description": "Generate unique identifiers for records, events, and correlation tracking"
    },
    {
      "name": "cryptography",
      "description": "Hash strings, encode/decode data — no key management required"
    },
    {
      "name": "time",
      "description": "Get current timestamps and parse scheduling expressions"
    },
    {
      "name": "validation",
      "description": "Validate emails, JSON payloads, and other structured data"
    },
    {
      "name": "conversion",
      "description": "Convert between units of measurement"
    },
    {
      "name": "text",
      "description": "Test regex patterns and process text"
    },
    {
      "name": "auth",
      "description": "Inspect authentication tokens without secret keys"
    },
    {
      "name": "meta",
      "description": "API health and tool discovery"
    }
  ],
  "paths": {
    "/api/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "List all available tools",
        "description": "Returns a complete list of all utility tools with their descriptions, parameters, and example usage. Use this endpoint first to discover available capabilities.",
        "tags": ["meta"],
        "responses": {
          "200": {
            "description": "Tool listing returned successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ToolListResponse" }
              }
            }
          }
        }
      }
    },
    "/api/tools/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check — verify the service is running",
        "description": "Returns the service health status, version, uptime, and number of available tools. Use this to verify the service is reachable before making other calls.",
        "tags": ["meta"],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HealthResponse" },
                "example": {
                  "success": true,
                  "tool": "health",
                  "result": {
                    "status": "healthy",
                    "service": "agent-utils",
                    "version": "1.0.0",
                    "uptime_seconds": 3600,
                    "tools_available": 10
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/uuid": {
      "get": {
        "operationId": "generateUUID",
        "summary": "Generate a UUID (v4 random or v7 time-sortable)",
        "description": "Generate a UUID for use as a unique identifier. Version 4 (default) is fully random and suitable for general-purpose IDs. Version 7 is time-sortable (timestamp prefix) and ideal for database primary keys where you need both uniqueness and chronological ordering.",
        "tags": ["identity"],
        "parameters": [
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "UUID version: 4 (random, default) or 7 (time-sortable for DB keys)",
            "schema": {
              "type": "string",
              "enum": ["4", "7"],
              "default": "4"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "UUID generated successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "uuid",
                  "result": {
                    "uuid": "550e8400-e29b-41d4-a716-446655440000",
                    "version": 4,
                    "format": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/hash": {
      "get": {
        "operationId": "hashString",
        "summary": "Hash a string (SHA-256, MD5, SHA-1, SHA-512)",
        "description": "Compute a cryptographic hash of any string. Use SHA-256 (default) for security contexts and integrity verification. Use MD5 only for non-security uses like cache keys or checksums for legacy systems. Returns the hex-encoded digest.",
        "tags": ["cryptography"],
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "The string to hash (UTF-8 encoded)",
            "schema": { "type": "string" },
            "example": "hello world"
          },
          {
            "name": "algo",
            "in": "query",
            "required": false,
            "description": "Hash algorithm",
            "schema": {
              "type": "string",
              "enum": ["sha256", "md5", "sha1", "sha512"],
              "default": "sha256"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hash computed successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "hash",
                  "result": {
                    "input": "hello world",
                    "algorithm": "sha256",
                    "hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe04294e576e4d6cdfe1aaec6a8",
                    "length_bits": 256,
                    "length_hex_chars": 64
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/base64": {
      "get": {
        "operationId": "base64EncodeDecode",
        "summary": "Encode or decode a string using Base64",
        "description": "Encode a plain string to Base64 (for embedding binary data in JSON, HTTP headers, or data URLs), or decode a Base64 string back to plain text. The encode response also includes the URL-safe variant (Base64url, with +/= replaced).",
        "tags": ["cryptography"],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "description": "encode: plain text → Base64. decode: Base64 → plain text",
            "schema": {
              "type": "string",
              "enum": ["encode", "decode"]
            }
          },
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "The string to encode or the Base64 string to decode",
            "schema": { "type": "string" },
            "example": "hello world"
          }
        ],
        "responses": {
          "200": {
            "description": "Encoding/decoding completed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/timestamp": {
      "get": {
        "operationId": "getCurrentTimestamp",
        "summary": "Get the current UTC timestamp",
        "description": "Returns the current server time in multiple formats simultaneously. Use format=iso for ISO 8601 (API-compatible), format=unix for Unix epoch seconds (database storage), format=human for readable UTC string, or format=all (default) to get all formats plus year/month/day/hour components.",
        "tags": ["time"],
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Output format: iso, unix, human, or all (default)",
            "schema": {
              "type": "string",
              "enum": ["iso", "unix", "human", "all"],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Timestamp returned successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "timestamp",
                  "result": {
                    "format": "all",
                    "iso": "2026-05-29T12:00:00.000Z",
                    "unix": 1748520000,
                    "unix_ms": 1748520000000,
                    "human": "Fri, 29 May 2026 12:00:00 GMT",
                    "year": 2026,
                    "month": 5,
                    "day": 29
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/validate/email": {
      "get": {
        "operationId": "validateEmail",
        "summary": "Validate an email address format",
        "description": "Check whether a string is a validly-formatted email address. Returns validity, the parsed local part and domain, whether it has subdomains, and a list of specific issues if invalid. Useful before storing or sending to email APIs.",
        "tags": ["validation"],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "Email address to validate",
            "schema": { "type": "string", "format": "email" },
            "example": "user@example.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Validation result returned (check result.valid)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "validate/email",
                  "result": {
                    "email": "user@example.com",
                    "valid": true,
                    "local_part": "user",
                    "domain": "example.com",
                    "has_subdomain": false,
                    "issues": null
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/validate/json": {
      "post": {
        "operationId": "validateJSON",
        "summary": "Validate and pretty-print a JSON payload",
        "description": "POST raw JSON text in the request body to validate it and receive a pretty-printed version. Returns the parsed object, formatted output, data type (object/array/string/number), character count, and key count. If invalid, returns the parse error with position context. Useful for normalizing JSON from tool outputs before downstream processing.",
        "tags": ["validation"],
        "requestBody": {
          "required": true,
          "description": "Raw JSON text to validate",
          "content": {
            "application/json": {
              "schema": { "type": "object" },
              "example": { "key": "value", "nested": { "num": 42 } }
            },
            "text/plain": {
              "schema": { "type": "string" },
              "example": "{\"key\": \"value\"}"
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result (check result.valid — success:true even when JSON is invalid)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" }
              }
            }
          }
        }
      }
    },
    "/api/tools/convert/units": {
      "get": {
        "operationId": "convertUnits",
        "summary": "Convert between units of measurement",
        "description": "Convert a numeric value between supported units. Supported conversions: km/miles/meters/feet (distance), kg/lbs/grams/ounces (weight), celsius/fahrenheit/kelvin (temperature), liters/gallons/ml (volume), bytes/kb/mb/gb/tb (digital storage). Pass the unit names as lowercase strings.",
        "tags": ["conversion"],
        "parameters": [
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "Numeric value to convert",
            "schema": { "type": "number" },
            "example": 100
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Source unit (e.g.: km, miles, meters, feet, kg, lbs, celsius, fahrenheit, kelvin, liters, gallons, bytes, kb, mb, gb, tb)",
            "schema": { "type": "string" },
            "example": "km"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Target unit",
            "schema": { "type": "string" },
            "example": "miles"
          }
        ],
        "responses": {
          "200": {
            "description": "Conversion result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "convert/units",
                  "result": {
                    "input_value": 100,
                    "input_unit": "km",
                    "output_value": 62.1371,
                    "output_unit": "miles",
                    "formatted": "100 km = 62.1371 miles"
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/regex/test": {
      "get": {
        "operationId": "regexTest",
        "summary": "Test a regular expression against an input string",
        "description": "Test a regex pattern against input text. Returns whether it matched, all captured groups, match positions, and (with flag g) all global matches. Use flags: g (find all matches), i (case-insensitive), m (multiline). Pattern should be provided without delimiters — just the pattern itself.",
        "tags": ["text"],
        "parameters": [
          {
            "name": "pattern",
            "in": "query",
            "required": true,
            "description": "Regular expression pattern (no delimiters, e.g.: \\d+ or [a-z]+@[a-z]+\\.com)",
            "schema": { "type": "string" },
            "example": "\\d+"
          },
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "Input string to test the pattern against",
            "schema": { "type": "string" },
            "example": "hello 42 world 99"
          },
          {
            "name": "flags",
            "in": "query",
            "required": false,
            "description": "Regex flags: g (global/all matches), i (case-insensitive), m (multiline), s (dot matches newline)",
            "schema": { "type": "string", "default": "" },
            "example": "g"
          }
        ],
        "responses": {
          "200": {
            "description": "Regex test result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/cron/describe": {
      "get": {
        "operationId": "cronDescribe",
        "summary": "Convert a cron expression to human-readable text",
        "description": "Parse a cron expression and return a natural language description plus the next 5 scheduled execution times in ISO 8601 UTC. Supports 5-field (minute hour day month weekday) and 6-field (second minute hour day month weekday) expressions. Use this to explain scheduled jobs to users or verify cron syntax before deploying.",
        "tags": ["time"],
        "parameters": [
          {
            "name": "expr",
            "in": "query",
            "required": true,
            "description": "Cron expression with 5 fields (minute hour day month weekday) e.g. '0 9 * * 1-5' for 9am weekdays",
            "schema": { "type": "string" },
            "example": "0 9 * * 1-5"
          }
        ],
        "responses": {
          "200": {
            "description": "Cron description and next run times",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "cron/describe",
                  "result": {
                    "expression": "0 9 * * 1-5",
                    "description": "At 09:00 AM, Monday through Friday",
                    "next_5_runs": [
                      "2026-06-01T09:00:00.000Z",
                      "2026-06-02T09:00:00.000Z",
                      "2026-06-03T09:00:00.000Z",
                      "2026-06-04T09:00:00.000Z",
                      "2026-06-05T09:00:00.000Z"
                    ],
                    "timezone": "UTC"
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/api/tools/jwt/decode": {
      "get": {
        "operationId": "jwtDecode",
        "summary": "Decode a JWT token (no secret required)",
        "description": "Decode a JWT (JSON Web Token) to inspect its header and payload claims without needing the signing secret. Returns the algorithm, token type, all payload claims, expiry status, issued-at time, and whether the token is currently expired. IMPORTANT: This does NOT verify the signature — never trust decoded claims for security decisions without proper signature verification.",
        "tags": ["auth"],
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "description": "JWT token string. Bearer prefix is automatically stripped if present.",
            "schema": { "type": "string" },
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTc0ODYwNDQwMH0.signature"
          }
        ],
        "responses": {
          "200": {
            "description": "JWT decoded successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StandardResponse" },
                "example": {
                  "success": true,
                  "tool": "jwt/decode",
                  "result": {
                    "header": { "alg": "HS256", "typ": "JWT" },
                    "payload": { "sub": "user_123", "exp": 1748604400, "iss": "myapp" },
                    "algorithm": "HS256",
                    "token_type": "JWT",
                    "issued_at": null,
                    "expires_at": "2026-05-30T12:00:00.000Z",
                    "is_expired": false,
                    "seconds_until_expiry": 84400,
                    "issuer": "myapp",
                    "subject": "user_123",
                    "signature_verified": false,
                    "signature_note": "Signature not verified — decode-only mode."
                  },
                  "timestamp": "2026-05-29T12:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "StandardResponse": {
        "type": "object",
        "required": ["success", "tool", "result", "timestamp"],
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the tool call succeeded"
          },
          "tool": {
            "type": "string",
            "description": "Name of the tool that was called"
          },
          "result": {
            "type": "object",
            "description": "Tool-specific result payload"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the response was generated"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["success", "tool", "error", "timestamp"],
        "properties": {
          "success": { "type": "boolean", "example": false },
          "tool": { "type": "string" },
          "error": { "type": "string", "description": "Human-readable error message" },
          "timestamp": { "type": "string", "format": "date-time" }
        }
      },
      "HealthResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/StandardResponse" },
          {
            "properties": {
              "result": {
                "type": "object",
                "properties": {
                  "status": { "type": "string", "example": "healthy" },
                  "service": { "type": "string", "example": "agent-utils" },
                  "version": { "type": "string", "example": "1.0.0" },
                  "uptime_seconds": { "type": "integer" },
                  "tools_available": { "type": "integer" }
                }
              }
            }
          }
        ]
      },
      "ToolListResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/StandardResponse" },
          {
            "properties": {
              "result": {
                "type": "object",
                "properties": {
                  "service": { "type": "string" },
                  "tools_count": { "type": "integer" },
                  "tools": { "type": "array", "items": { "type": "object" } }
                }
              }
            }
          }
        ]
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request — missing or invalid parameter",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    }
  }
}
