{
  "openapi": "3.1.0",
  "info": {
    "title": "FabTally Utility Belt — deterministic micro-utilities for agents",
    "version": "1.0.0",
    "description": "A bundle of fast, deterministic micro-utilities AI agents call constantly — timezone/DST, cron, iCal RRULE, unit & live currency conversion, safe regex, text diff, JSON-Schema validation, hashing/encoding/IDs, and business-day date math. Six utilities are FREE and unlimited; seven are $0.001/call via x402 (USDC on Base) or a prepaid credit key, each with a rate-limited free teaser. Stateless, no storage, sub-100ms, bad-input never charged. Also available as a standalone MCP server.",
    "x-guidance": "Free unlimited: POST /v1/convert, /v1/text, /v1/hash, /v1/encode, /v1/id, /v1/regex. Paid $0.001 (x402 USDC on Base, or prepaid X-FabTally-Key): POST /v1/timezone, /v1/cron, /v1/rrule, /v1/currency, /v1/diff, /v1/jsonschema, /v1/datemath — each has a rate-limited /free teaser. Unpaid paid-calls return an x402 402 challenge; pay and retry with the X-PAYMENT header. Bad input -> 400, never charged.",
    "contact": {
      "email": "hello@fabtally.com"
    }
  },
  "servers": [
    {
      "url": "https://belt.fabtally.com"
    }
  ],
  "paths": {
    "/agent/overview": {
      "get": {
        "operationId": "overview",
        "summary": "Capabilities, pricing, payment info (free)",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Overview"
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Health (free)",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/convert": {
      "post": {
        "operationId": "convert",
        "summary": "convert (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Unit conversion across length, mass, temperature, volume, data, time, area, speed, angle, pressure, energy.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "value": 100,
                "from": "c",
                "to": "f"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/text": {
      "post": {
        "operationId": "text",
        "summary": "text (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "slugify, case-convert (camel/pascal/snake/kebab/constant/dot/path/title/sentence/upper/lower) and {{template}} fill.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "op": "slugify",
                "text": "Héllo, World!"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/hash": {
      "post": {
        "operationId": "hash",
        "summary": "hash (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "sha256/sha512/sha384/sha1/md5/sha3-256/keccak256/ripemd160, optional HMAC, hex/base64 output.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "algorithm": "sha256",
                "text": "hello"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/encode": {
      "post": {
        "operationId": "encode",
        "summary": "encode (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "base64 / base64url / hex / url / html encode & decode.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "op": "base64-encode",
                "text": "hello"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/id": {
      "post": {
        "operationId": "id",
        "summary": "id (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Generate uuid v4/v7, ULID, nanoid, or random hex/base64url/int (count up to 1000).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "kind": "uuidv7",
                "count": 2
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/regex": {
      "post": {
        "operationId": "regex",
        "summary": "regex (free)",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "test/match/extract/replace with catastrophic-backtracking protection (runs in a killable worker with a hard timeout).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "pattern": "(\\d+)",
                "flags": "g",
                "input": "a12 b34",
                "op": "extract"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input"
          }
        }
      }
    },
    "/v1/timezone": {
      "post": {
        "operationId": "timezone",
        "summary": "timezone (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Convert an instant between IANA time zones with historically-correct DST. Give a datetime (ISO 8601 or epoch) + from_zone + to_zone; get the converted datetime, UTC offsets, tz abbreviations, DST flags, and the offset difference. Deterministic, sub-100ms, no storage.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/timezone",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "datetime": "2021-03-14T01:30:00",
                "from_zone": "America/New_York",
                "to_zone": "Europe/London"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/timezone/free": {
      "post": {
        "operationId": "timezone_free",
        "summary": "timezone — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for timezone (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "datetime": "2021-03-14T01:30:00",
                "from_zone": "America/New_York",
                "to_zone": "Europe/London"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/cron": {
      "post": {
        "operationId": "cron",
        "summary": "cron (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Parse a cron expression and return the next N run times plus a plain-English description. Give a 5- or 6-field cron `expression` (+ optional IANA `timezone`, `count`, `from`). Deterministic.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/cron",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "expression": "0 9 * * 1-5",
                "timezone": "UTC",
                "count": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/cron/free": {
      "post": {
        "operationId": "cron_free",
        "summary": "cron — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for cron (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "expression": "0 9 * * 1-5",
                "timezone": "UTC",
                "count": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/rrule": {
      "post": {
        "operationId": "rrule",
        "summary": "rrule (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Expand an iCal RRULE recurrence into its next N occurrences. Give an `rrule` string (RFC 5545, e.g. FREQ=WEEKLY;BYDAY=MO,WE;COUNT=10) + optional `after`, `count`, `timezone`.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/rrule",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "rrule": "FREQ=WEEKLY;BYDAY=MO,WE;COUNT=10",
                "count": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/rrule/free": {
      "post": {
        "operationId": "rrule_free",
        "summary": "rrule — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for rrule (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "rrule": "FREQ=WEEKLY;BYDAY=MO,WE;COUNT=10",
                "count": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/currency": {
      "post": {
        "operationId": "currency",
        "summary": "currency (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Live currency conversion at reference/mid-market rates from a keyless public central-bank feed (ECB), cached in-memory. Give `amount` + `from` + `to` ISO-4217 codes. Informational, not a dealable quote.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/currency",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "amount": 100,
                "from": "USD",
                "to": "EUR"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/currency/free": {
      "post": {
        "operationId": "currency_free",
        "summary": "currency — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for currency (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "amount": 100,
                "from": "USD",
                "to": "EUR"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/diff": {
      "post": {
        "operationId": "diff",
        "summary": "diff (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Text diff: a unified patch plus a structured op-list (add/remove/equal) and add/remove/hunk stats. Give `a` + `b` (+ optional `mode` lines|words|chars, `context`, labels). Deterministic.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/diff",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "a": "line1\nline2\n",
                "b": "line1\nline2 changed\n"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/diff/free": {
      "post": {
        "operationId": "diff_free",
        "summary": "diff — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for diff (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "a": "line1\nline2\n",
                "b": "line1\nline2 changed\n"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/jsonschema": {
      "post": {
        "operationId": "jsonschema",
        "summary": "jsonschema (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Validate a value against a JSON Schema (draft 2020-12) and explain every error in plain English (which property, what was wrong, allowed values). Give `schema` + `data`.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/jsonschema",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "schema": {
                  "type": "object",
                  "required": [
                    "x"
                  ],
                  "properties": {
                    "x": {
                      "type": "integer"
                    }
                  }
                },
                "data": {
                  "x": "nope"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/jsonschema/free": {
      "post": {
        "operationId": "jsonschema_free",
        "summary": "jsonschema — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for jsonschema (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "schema": {
                  "type": "object",
                  "required": [
                    "x"
                  ],
                  "properties": {
                    "x": {
                      "type": "integer"
                    }
                  }
                },
                "data": {
                  "x": "nope"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    },
    "/v1/datemath": {
      "post": {
        "operationId": "datemath",
        "summary": "datemath (paid, $0.001 USDC on Base)",
        "tags": [
          "Paid"
        ],
        "description": "Calendar date math: add/subtract an ISO-8601 duration, diff two datetimes into chosen units, or add/diff business days (configurable weekend + holiday list). Give `op` + the relevant fields.",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.001000"
          },
          "protocols": [
            {
              "x402": {
                "scheme": "exact",
                "network": "eip155:8453",
                "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "maxAmountRequired": "1000",
                "payTo": "0xccB5d25C698FdfdaA7B21d54088774cF512A90e3",
                "resource": "https://belt.fabtally.com/v1/datemath",
                "facilitator": "https://facilitator.daydreams.systems",
                "maxTimeoutSeconds": 60
              }
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "op": "business-add",
                "date": "2026-07-31",
                "days": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Bad input (never charged)"
          },
          "402": {
            "description": "Payment Required (x402 v2 challenge)"
          }
        }
      }
    },
    "/v1/datemath/free": {
      "post": {
        "operationId": "datemath_free",
        "summary": "datemath — rate-limited free teaser",
        "tags": [
          "Free"
        ],
        "security": [],
        "description": "Free teaser for datemath (daily per-IP quota).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "op": "business-add",
                "date": "2026-07-31",
                "days": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Teaser result"
          },
          "429": {
            "description": "Free daily quota exceeded"
          }
        }
      }
    }
  }
}