{
  "openapi": "3.1.0",
  "info": {
    "title": "FreeForAgents",
    "version": "1.0.0",
    "description": "Free, zero-auth utility APIs for humans and AI agents. No API keys, no signup. Docs in markdown at /docs/<endpoint>.md."
  },
  "servers": [
    {
      "url": "https://freeforagents.dev"
    }
  ],
  "paths": {
    "/ip": {
      "get": {
        "summary": "Look up your IP address and geolocation.",
        "description": "Returns the caller's public IP address and geolocation data (country, city, region, coordinates, timezone, ASN) derived from Cloudflare's edge network. No parameters required — call it from any client and it inspects the incoming request.",
        "parameters": [],
        "tags": [
          "ip"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "ip": "203.0.113.42",
                  "country": "US",
                  "city": "San Francisco",
                  "region": "California",
                  "postal_code": "94102",
                  "latitude": 37.7749,
                  "longitude": -122.4194,
                  "timezone": "America/Los_Angeles",
                  "asn": 7922,
                  "as_organization": "Comcast Cable"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/uuid": {
      "get": {
        "summary": "Generate RFC 4122 version 4 UUIDs.",
        "description": "Generates cryptographically random UUIDs (version 4) using the Web Crypto API.",
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many UUIDs to generate (default 1, max 100).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "uuid"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "count": 2,
                  "uuids": [
                    "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
                    "9b2f1c3e-8a4d-4c2a-b6f0-1d2e3f4a5b6c"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/ulid": {
      "get": {
        "summary": "Generate ULIDs (sortable unique identifiers).",
        "description": "Generates ULIDs per the ulid spec: a 48-bit timestamp prefix followed by 80 bits of randomness, encoded in Crockford Base32. ULIDs sort lexicographically by creation time, making them ideal for database keys.",
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many ULIDs to generate (default 1, max 100).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "ulid"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "count": 1,
                  "ulids": [
                    "01JF8ZK3P2QWERTY5MNBHY6VCX"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/hash": {
      "get": {
        "summary": "Hash text with SHA-1/256/384/512.",
        "description": "Computes the hex digest of the given text using Web Crypto SHA algorithms. MD5 is intentionally not supported (insecure and unavailable in Web Crypto).",
        "parameters": [
          {
            "name": "text",
            "in": "query",
            "required": true,
            "description": "The text to hash.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "algo",
            "in": "query",
            "required": false,
            "description": "One of sha-1, sha-256, sha-384, sha-512 (default sha-256).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "hash"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "algo": "sha-256",
                  "text": "hello",
                  "digest": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/base64": {
      "get": {
        "summary": "Encode or decode Base64 strings.",
        "description": "Encodes text to Base64, or decodes Base64 back to UTF-8 text.",
        "parameters": [
          {
            "name": "text",
            "in": "query",
            "required": true,
            "description": "The input text.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "'encode' (default) or 'decode'.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "base64"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "mode": "encode",
                  "input": "hello world",
                  "result": "aGVsbG8gd29ybGQ="
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/convert": {
      "get": {
        "summary": "Convert between units (length, mass, volume, area, data, speed, time, temperature).",
        "description": "General-purpose unit conversion. Units are resolved across categories with common aliases accepted (e.g. 'kilometers', 'km', 'kilometres' all work). Temperature converts between c, f and k.",
        "parameters": [
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "The numeric value to convert.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Source unit (e.g. kg, mi, c).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Target unit (e.g. lb, km, f).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "convert"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "value": 10,
                  "from": "kg",
                  "to": "lb",
                  "result": 22.046226218487757
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/time": {
      "get": {
        "summary": "Current time in any timezone.",
        "description": "Returns the current UTC epoch timestamps plus fully-parsed local time components for the requested IANA timezone.",
        "parameters": [
          {
            "name": "tz",
            "in": "query",
            "required": false,
            "description": "IANA timezone name (default 'UTC'), e.g. America/New_York.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "time"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "utc_epoch_seconds": 1755892800,
                  "utc_iso": "2026-08-22T18:40:00.000Z",
                  "timezone": "Asia/Tokyo",
                  "local": {
                    "year": 2026,
                    "month": 8,
                    "day": 23,
                    "hour": 3,
                    "minute": 40,
                    "second": 0,
                    "weekday": "Sunday",
                    "date": "2026-08-23",
                    "time": "03:40:00"
                  },
                  "utc_offset": "GMT+9"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/timestamp": {
      "get": {
        "summary": "Current Unix timestamp.",
        "description": "Returns the current time as Unix epoch seconds, milliseconds and ISO 8601. Useful for clock sanity checks in scripts and agents.",
        "parameters": [],
        "tags": [
          "timestamp"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "epoch_seconds": 1755892800,
                  "epoch_millis": 1755892800123,
                  "iso_8601": "2026-08-22T18:40:00.123Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/random": {
      "get": {
        "summary": "Cryptographically secure random integers.",
        "description": "Generates random integers between min and max (inclusive) using a CSPRNG. Set decimals=true for random floats in [min, max).",
        "parameters": [
          {
            "name": "min",
            "in": "query",
            "required": false,
            "description": "Lower bound inclusive (default 0).",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "max",
            "in": "query",
            "required": false,
            "description": "Upper bound inclusive (default 100).",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many numbers (default 1, max 1000).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "decimals",
            "in": "query",
            "required": false,
            "description": "Return floats instead of integers (default false).",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "tags": [
          "random"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "min": 1,
                  "max": 6,
                  "count": 2,
                  "values": [
                    4,
                    1
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/dice": {
      "get": {
        "summary": "Roll dice.",
        "description": "Simulates dice rolls with any number of sides. Perfect for games, decisions and settling arguments fairly.",
        "parameters": [
          {
            "name": "rolls",
            "in": "query",
            "required": false,
            "description": "Number of dice to roll (default 1, max 20).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "sides",
            "in": "query",
            "required": false,
            "description": "Sides per die (default 6, max 1000).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "dice"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "rolls": [
                    17,
                    3
                  ],
                  "sides": 20,
                  "total": 20,
                  "count": 2
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/password": {
      "get": {
        "summary": "Generate strong random passwords.",
        "description": "Generates passwords drawn from upper/lowercase letters, digits and symbols, guaranteed to include at least one of each character class.",
        "parameters": [
          {
            "name": "length",
            "in": "query",
            "required": false,
            "description": "Password length (default 16, max 128).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many passwords (default 1, max 10).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "password"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "length": 16,
                  "passwords": [
                    "K#9mVx2!pLq8@wZ4"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/lorem": {
      "get": {
        "summary": "Lorem ipsum placeholder text.",
        "description": "Generates lorem ipsum style paragraphs built from a classic word bank. Deterministically starts with 'Lorem ipsum dolor sit amet'.",
        "parameters": [
          {
            "name": "paragraphs",
            "in": "query",
            "required": false,
            "description": "Number of paragraphs (default 1, max 10).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "lorem"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "paragraphs": [
                    "Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor."
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/emoji": {
      "get": {
        "summary": "Random emoji.",
        "description": "Returns random emoji characters with their names from a curated library of 100+.",
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many emoji (default 5, max 50).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "emoji"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "emoji": [
                    {
                      "char": "🚀",
                      "name": "rocket"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/joke": {
      "get": {
        "summary": "Random clean programming joke.",
        "description": "Returns a random joke from a hand-curated list of clean, work-safe jokes with a tech/programming flavour.",
        "parameters": [],
        "tags": [
          "joke"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "id": 3,
                  "joke": "A SQL query walks into a bar, approaches two tables and asks: may I join you?"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/fact": {
      "get": {
        "summary": "Random fun fact.",
        "description": "Returns a random verified fun fact — great conversation starters and test payloads.",
        "parameters": [],
        "tags": [
          "fact"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "id": 1,
                  "fact": "Octopuses have three hearts and blue blood."
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/quote": {
      "get": {
        "summary": "Random inspirational quote.",
        "description": "Returns a random quote with author attribution from a curated public list.",
        "parameters": [],
        "tags": [
          "quote"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "id": 0,
                  "quote": {
                    "text": "Talk is cheap. Show me the code.",
                    "author": "Linus Torvalds"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/holidays": {
      "get": {
        "summary": "Public holidays by country and year.",
        "description": "Lists public holidays for the requested country and year. Dates are computed locally (including Easter-based holidays via the anonymous Gregorian algorithm). Supported countries: US, GB, CA, AU, NZ, IN. Years supported: 2000–2100.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO country code (default US).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Calendar year (default current year).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "holidays"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "country": "IN",
                  "year": 2026,
                  "holidays": [
                    {
                      "date": "2026-01-26",
                      "name": "Republic Day"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/fx": {
      "get": {
        "summary": "Foreign exchange rates (daily, no key).",
        "description": "Returns latest FX exchange rates against the requested base currency, sourced from open.er-api.com and cached at the edge for 1 hour. Cross rates are computed for non-USD bases.",
        "parameters": [
          {
            "name": "base",
            "in": "query",
            "required": false,
            "description": "Base currency code (default USD), e.g. EUR, GBP, JPY.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "fx"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "base": "USD",
                  "last_update_utc": "Sat, 22 Aug 2026 00:00:01 +0000",
                  "rates": {
                    "EUR": 0.92,
                    "GBP": 0.79,
                    "JPY": 149.5
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/headers": {
      "get": {
        "summary": "Echo your request headers.",
        "description": "Returns all request headers as seen by the server. Invaluable for debugging proxies, webhooks, API gateways and agent user-agents.",
        "parameters": [],
        "tags": [
          "headers"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "headers": {
                    "user-agent": "curl/8.7.1",
                    "accept": "*/*"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/json": {
      "get": {
        "summary": "Fetch any URL and get parsed JSON back.",
        "description": "A minimal JSON proxy: fetches an https:// URL and returns its parsed JSON body under 'data'. Safety limits: https only, private/internal hosts blocked, 8s timeout, 500 KB max response.",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "The https:// URL to fetch. Must return JSON.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "json"
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "source_url": "https://api.github.com/zen",
                  "content_type": "application/json; charset=utf-8",
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    }
  }
}