API Documentation

REST API reference for all UtilsToGo micro-utilities. Base URL: https://utils.bithub.org/api/v1

Authentication

Pass your API key in the X-API-Key header. Get your key from the Account page.

X-API-Key: utg_your_api_key_here

All stateless tool endpoints (text, encoding, hash, etc.) are also accessible without authentication, subject to per-IP rate limits.

Rate Limits

Tier API requests / min URLs / month Redirects / month
Anonymous (IP)60
Free (API key)30031,000
Starter30010020,000
Pro3001,000100,000

Rate limit errors return 429 Too Many Requests.

MCP Integration

UtilsToGo exposes a Model Context Protocol server. Connect any MCP-compatible client (Claude Desktop, Cursor, Zed, etc.).

{
  "mcpServers": {
    "utilstogo": {
      "url": "https://utils.bithub.org/mcp",
      "transport": "streamable-http"
    }
  }
}

Auto-discovery via /.well-known/mcp.json for WebMCP-compatible browser extensions.

Available MCP Tools

create_short_url(url, custom_code?)
get_url_stats(code)
generate_qr_code(content, qr_type?, label?)
transform_text(text, operation)
encode_decode(input, format, direction?)
math_calculate(expression)
math_convert_units(value, from_unit, to_unit, category)
math_generate_uuid(count?, version?)
math_statistics(data)
security_generate_password(...)
security_verify_hash(input, hash, algorithm?)
security_inspect_jwt(token)
security_build_csp(directives)
security_check_cors(url, origin?)
network_ip_lookup(ip?)
network_dns_lookup(domain, record_type?)
network_whois(domain)
network_check_ports(host, ports?, timeout?)
network_http_headers(url)
network_ssl_certificate(hostname)
network_ping(host)
link_parse_url(url)
link_check_url(url)
link_build_utm(url, source, medium, campaign)
link_extract_meta_tags(url)
link_og_preview(url)
link_fetch_favicon(domain)
colour_convert(hex?, r?, g?, b?, h?, s?, l?)
colour_name(hex)
colour_contrast(hex1, hex2)
colour_palette(base_hex, scheme?)
colour_mix(hex1, hex2, weight?)
code_highlight(code, language, theme?)
code_minify(code, language)
code_format_sql(sql)
code_stats(code, language?)
diff_text(original, modified, style?)
diff_apply_patch(original, patch)
diff_similarity(text1, text2)
diff_merge(base, ours, theirs)
pdf_extract_text(pdf_base64, pages?)
pdf_metadata(pdf_base64)
ai_summarise(text, style?)
ai_sentiment(text)
ai_detect_language(text)
ai_translate(text, target_language)
ai_grammar(text)
webhook_create(url, events, user_id)
webhook_list(user_id)
webhook_delete(webhook_id, user_id)
webhook_deliveries(webhook_id, user_id)
webhook_retry(webhook_id, delivery_id, user_id)
list_services()

Short URLs

POST/api/v1/urls

Create a shortened URL.

// Request
{ "url": "https://example.com/long", "custom_code": "my-slug" }
// Response
{ "id": "...", "code": "2BKxmR", "short_url": "https://bbrl.uk/2BKxmR", "target_url": "..." }
curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/urls \
  -H "X-API-Key: utg_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

# Python
import httpx
r = httpx.post("https://utils.bithub.org/api/v1/urls",
    headers={"X-API-Key": "utg_your_key"},
    json={"url": "https://example.com"})
print(r.json()["short_url"])

GET/api/v1/urls

List your short URLs with click counts.

curl -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/urls
→ [{"id":1,"short_code":"abc123","target_url":"https://example.com","clicks":42}]

GET/api/v1/urls/{id}/stats

Analytics for a URL. Free: count only. Starter: devices + referrers. Pro: full time-series.

curl -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/urls/1/stats
→ {"short_code":"abc123","clicks":42,"referrers":[{"source":"twitter.com","count":18}],"countries":[{"country":"GB","count":25}]}

DELETE/api/v1/urls/{id}

Delete a short URL and its click history.

curl -X DELETE -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/urls/1
→ {"deleted": true}

QR Codes

POST/api/v1/qr

Generate a QR code. qr_type: url | text | wifi | vcard

{ "qr_type": "url", "content": "https://example.com", "label": "My QR", "format": "png" }
curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/qr \
  -H "X-API-Key: utg_your_key" \
  -H "Content-Type: application/json" \
  -d '{"qr_type":"url","content":"https://example.com"}'

# Fetch the QR image
curl https://utils.bithub.org/api/v1/qr/{id}/image -o qr.png

GET/api/v1/qr/{id}/image

Returns the QR code as a PNG image.

curl / Python
# curl
curl -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/qr/123/image -o qr.png

# Python
import httpx
r = httpx.get("https://utils.bithub.org/api/v1/qr/123/image",
    headers={"X-API-Key": "utg_your_key"})
open("qr.png", "wb").write(r.content)

Text Utilities

POST/api/v1/text/transform

Case conversion, slug, wrap. operation: uppercase | lowercase | titlecase | sentencecase | slug | wrap

{ "text": "hello world", "operation": "titlecase", "width": 80 }
→ { "result": "Hello World", "operation": "titlecase" }

POST/api/v1/text/count

Word, character, sentence, and paragraph counts.

{ "text": "Hello world" }
→ {"chars":11,"words":2,"lines":1,"sentences":1}

POST/api/v1/text/readability

Flesch-Kincaid, Gunning Fog, Coleman-Liau scores.

{ "text": "The quick brown fox jumps over the lazy dog." }
→ {"flesch_score":80.1,"grade_level":"6th","reading_time_seconds":2}

POST/api/v1/text/lorem

Generate Lorem Ipsum. { "count": 3, "unit": "paragraphs" }

{ "paragraphs": 2, "words_per_paragraph": 50 }
→ {"text":"Lorem ipsum dolor sit amet, consectetur adipiscing elit..."}

POST/api/v1/text/regex

Test a regex pattern against input text. Returns all matches with positions.

{ "text": "foo bar baz", "pattern": "\\b\\w{3}\\b", "flags": "g" }
→ {"matches":["foo","bar","baz"],"count":3}

POST/api/v1/text/markdown

Convert Markdown to sanitised HTML.

{ "markdown": "# Hello\n**bold**" }
→ {"html":"<h1>Hello</h1>\n<p><strong>bold</strong></p>"}

POST/api/v1/text/html2text

Strip HTML tags and extract plain text.

{ "html": "<h1>Hello</h1><p>World</p>" }
→ {"text":"Hello\n\nWorld"}

POST/api/v1/text/escape

Escape/unescape for json | html | url | sql.

{ "text": "<script>alert('xss')</script>", "target": "html" }
→ {"escaped":"&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;"}

Encoding / Decoding

POST/api/v1/encode/base64

Base64 encode or decode. direction: encode | decode

{ "input": "Hello World", "direction": "encode" }
→ { "result": "SGVsbG8gV29ybGQ=", "direction": "encode" }
curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/encode/base64 \
  -H "Content-Type: application/json" \
  -d '{"input":"Hello World","direction":"encode"}'

# Python
import httpx
r = httpx.post("https://utils.bithub.org/api/v1/encode/base64",
    json={"input": "Hello World", "direction": "encode"})
print(r.json()["result"])  # SGVsbG8gV29ybGQ=

POST/api/v1/encode/base32

Base32 encode/decode.

{ "text": "Hello", "operation": "encode" }
→ {"result":"JBSWY3DP"}

POST/api/v1/encode/url

URL percent-encode/decode.

{ "text": "hello world & more", "operation": "encode" }
→ {"result":"hello+world+%26+more"}

POST/api/v1/encode/html

HTML entity encode/decode.

{ "text": "<b>bold</b>", "operation": "encode" }
→ {"result":"&lt;b&gt;bold&lt;/b&gt;"}

POST/api/v1/encode/jwt

Decode and inspect a JWT token (header + payload, no verification).

{ "payload": {"sub":"123","name":"Alice"}, "secret": "mysecret" }
→ {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiQWxpY2UifQ..."}

POST/api/v1/encode/hex

Hex encode/decode.

{ "text": "Hello", "operation": "encode" }
→ {"result":"48656c6c6f"}

POST/api/v1/encode/rot13

Apply ROT13 to text.

{ "text": "Hello World" }
→ {"result":"Uryyb Jbeyq"}

Hash / Checksum

POST/api/v1/hash/generate

Hash text. algorithm: md5 | sha1 | sha256 | sha512 | sha224 | sha384

{ "input": "hello", "algorithm": "sha256" }
→ { "hash": "2cf24dba5f...", "algorithm": "sha256", "input_length": 5 }

POST/api/v1/hash/hmac

{ "input": "...", "key": "secret", "algorithm": "sha256" }

{ "text": "message", "key": "secret", "algorithm": "sha256" }
→ {"hmac":"2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b"}

POST/api/v1/hash/crc32

CRC32 checksum of text.

{ "text": "Hello" }
→ {"crc32":"f7d18982","decimal":4157704578}

POST/api/v1/hash/bcrypt

bcrypt hash/verify. operation: hash | verify

{ "text": "mypassword", "rounds": 12 }
→ {"hash":"$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/HS.iK0i"}

Data Conversion

POST/api/v1/convert/json

Format or minify JSON. operation: format | minify | validate

{ "input": "{\"a\":1}", "operation": "format", "indent": 2 }

POST/api/v1/convert/yaml

JSON ↔ YAML. direction: json_to_yaml | yaml_to_json

{ "input": "{\"name\":\"Alice\",\"age\":30}", "from": "json", "to": "yaml" }
→ {"result":"name: Alice\nage: 30\n"}

POST/api/v1/convert/xml

JSON ↔ XML.

{ "input": "{\"root\":{\"name\":\"Alice\"}}", "from": "json", "to": "xml" }
→ {"result":"<root><name>Alice</name></root>"}

POST/api/v1/convert/csv

CSV ↔ JSON array.

{ "input": "[{\"name\":\"Alice\",\"age\":30}]", "from": "json", "to": "csv" }
→ {"result":"name,age\nAlice,30\n"}

POST/api/v1/convert/toml

TOML → JSON.

{ "input": "{\"title\":\"Config\",\"port\":8080}", "from": "json", "to": "toml" }
→ {"result":"title = \"Config\"\nport = 8080\n"}

POST/api/v1/convert/ini

INI → JSON.

{ "input": "{\"db\":{\"host\":\"localhost\",\"port\":\"5432\"}}", "from": "json", "to": "ini" }
→ {"result":"[db]\nhost = localhost\nport = 5432\n"}

Date / Time

POST/api/v1/datetime/timestamp

Unix timestamp ↔ ISO 8601.

{ "unix": 1700000000 }  →  { "iso": "2023-11-14T22:13:20+00:00", ... }
{ "iso": "2023-11-14T22:13:20Z" }  →  { "unix": 1700000000, ... }

POST/api/v1/datetime/timezone

{ "datetime": "2026-01-15T12:00:00", "from_tz": "UTC", "to_tz": "America/New_York" }

{ "timestamp": 1700000000, "from_tz": "UTC", "to_tz": "America/New_York" }
→ {"converted":"2023-11-14T17:13:20-05:00","offset":"-05:00"}

POST/api/v1/datetime/diff

Days, weeks, months between two dates.

{ "start": "2024-01-01", "end": "2024-12-31" }
→ {"days":365,"weeks":52,"months":12,"years":1}

POST/api/v1/datetime/cron

Parse a cron expression and list next N run times.

{ "expression": "0 9 * * MON-FRI" }
→ {"next_runs":["2024-11-18T09:00:00","2024-11-19T09:00:00"],"description":"At 09:00 on every day-of-week from Monday through Friday"}

POST/api/v1/datetime/relative

Convert a date to "2 hours ago" / "in 3 days".

{ "timestamp": 1700000000 }
→ {"relative":"2 months ago","absolute":"2023-11-14T22:13:20Z"}

POST/api/v1/datetime/businessdays

Business days between two dates (excludes weekends).

{ "start": "2024-01-01", "end": "2024-01-31", "country": "GB" }
→ {"business_days":23,"holidays":["2024-01-01"]}

Math / Statistics

POST/api/v1/math/calc

Safe expression evaluator. Supports sqrt, sin, log, pi, factorial, etc.

{ "expression": "sqrt(2) * pi" }  →  { "result": 4.442882938..., "expression": "sqrt(2) * pi" }

POST/api/v1/math/convert

{ "value": 100, "from_unit": "km", "to_unit": "mi", "category": "length" }. Categories: length weight volume speed area data temperature

{ "value": 100, "from": "km", "to": "miles" }
→ {"result":62.137,"from_unit":"km","to_unit":"miles"}

POST/api/v1/math/percentage

Percentage calculations — of, change, increase/decrease.

{ "value": 75, "total": 200 }
→ {"percentage":37.5,"formatted":"37.5%"}

POST/api/v1/math/random

{ "min": 1, "max": 100, "count": 5, "type": "integer" }

{ "min": 1, "max": 100 }
→ {"value":42}

POST/api/v1/math/uuid

{ "count": 5, "version": 4 }

{}
→ {"uuid":"550e8400-e29b-41d4-a716-446655440000","version":4}

POST/api/v1/math/stats

Mean, median, mode, std dev, min, max, percentiles. { "data": [1,2,3,4,5] }

{ "numbers": [4,8,15,16,23,42] }
→ {"mean":18,"median":15.5,"std_dev":13.07,"min":4,"max":42}

POST/api/v1/math/baseconvert

{ "value": "255", "from_base": 10, "to_base": 16 }

{ "value": "255", "from_base": 10, "to_base": 16 }
→ {"result":"ff","from_base":10,"to_base":16}

Security

POST/api/v1/security/password

Generate cryptographically secure passwords.

{ "length": 24, "uppercase": true, "symbols": true, "count": 3 }
→ { "passwords": ["Xk#9mP...", ...], "entropy_bits": 157.6 }

POST/api/v1/security/verify

Verify text against a hash. { "input": "hello", "hash": "2cf24d...", "algorithm": "sha256" }

{ "hash": "$2b$12$LQv3c1yqBWVHxkd0LHAkCO...", "text": "mypassword" }
→ {"match":true,"algorithm":"bcrypt"}

POST/api/v1/security/cors

Check CORS policy for a URL. { "url": "https://api.example.com", "origin": "https://myapp.com" }

{ "url": "https://api.example.com", "origin": "https://app.example.com" }
→ {"cors_enabled":true,"allow_origin":"*","allow_methods":["GET","POST"]}

POST/api/v1/security/csp

Build a Content-Security-Policy header. { "directives": {"default-src": ["'self'"], "script-src": ["'self'", "cdn.example.com"]} }

{ "directives": {"default-src":["'self'"],"script-src":["'self'","https://cdn.example.com"]} }
→ {"policy":"default-src 'self'; script-src 'self' https://cdn.example.com","violations":[]}

POST/api/v1/security/jwt

Decode and inspect a JWT — header, payload, claims, expiry.

{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk8azHhEqf-Q1w" }
→ {"header":{"alg":"HS256","typ":"JWT"},"payload":{"sub":"1234567890","name":"John Doe","iat":1516239022},"expired":false}

Network

POST/api/v1/network/ip

Geolocate an IP — country, region, city, ISP, ASN, timezone. Omit ip for your own.

{ "ip": "8.8.8.8" }
→ { "ip": "8.8.8.8", "country": "United States", "city": "Mountain View", "isp": "Google LLC", ... }
curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/network/ip \
  -H "Content-Type: application/json" \
  -d '{"ip":"8.8.8.8"}'

# Python
import httpx
r = httpx.post("https://utils.bithub.org/api/v1/network/ip", json={"ip": "8.8.8.8"})
print(r.json()["country"])

POST/api/v1/network/dns

{ "domain": "example.com", "record_type": "MX" }. Types: A AAAA MX TXT NS CNAME SOA CAA SRV PTR

{ "domain": "example.com", "record_type": "A" }
→ {"records":[{"type":"A","value":"93.184.216.34","ttl":86400}]}

POST/api/v1/network/whois

WHOIS/RDAP for a domain — registrar, dates, nameservers.

{ "domain": "example.com" }
→ {"registrar":"IANA","created":"1995-08-14","expires":"2024-08-13","nameservers":["a.iana-servers.net"]}

POST/api/v1/network/port

{ "host": "example.com", "ports": [80, 443, 22], "timeout": 3 }. Up to 20 ports.

{ "host": "example.com", "port": 443 }
→ {"open":true,"host":"example.com","port":443,"response_ms":45}

POST/api/v1/network/headers

HTTP response headers + security score (HSTS, CSP, X-Frame-Options, etc.).

{ "url": "https://example.com" }
→ {"status":200,"headers":{"content-type":"text/html","server":"ECS"}}

POST/api/v1/network/ssl

TLS certificate details — expiry, issuer, SANs, days remaining.

{ "domain": "example.com" }
→ {"valid":true,"expires":"2025-03-15","issuer":"DigiCert Inc","days_remaining":120}

POST/api/v1/network/ping

TCP latency to a host (min/avg/max, packet loss). { "host": "google.com", "port": 80, "count": 4 }

{ "host": "example.com", "port": 80, "count": 3 }
→ {"reachable":true,"avg_ms":12.4,"min_ms":11.1,"max_ms":14.2}

Image Utilities

All image endpoints accept multipart/form-data with a file field (max 20 MB). Binary endpoints return the processed image directly.

POST/api/v1/image/resize

Resize an image. Returns binary image.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/resize \
  -F "file=@photo.jpg" -F "width=800" -F "height=600" \
  -o resized.jpg

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/resize",
        files={"file": f}, data={"width": 800, "height": 600})
open("resized.jpg", "wb").write(r.content)

POST/api/v1/image/crop

Crop to a region. Form fields: x y width height.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/crop \
  -F "file=@photo.jpg" -F "x=100" -F "y=50" -F "width=400" -F "height=300" \
  -o cropped.jpg

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/crop",
        files={"file": f}, data={"x": 100, "y": 50, "width": 400, "height": 300})
open("cropped.jpg", "wb").write(r.content)

POST/api/v1/image/compress

Reduce file size. quality 1–95 for JPEG/WebP. optimise=true for PNG.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/compress \
  -F "file=@photo.jpg" -F "quality=75" \
  -o compressed.jpg

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/compress",
        files={"file": f}, data={"quality": 75})
open("compressed.jpg", "wb").write(r.content)

POST/api/v1/image/convert

Convert format. format: png | jpeg | webp | gif.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/convert \
  -F "file=@photo.jpg" -F "format=webp" \
  -o photo.webp

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/convert",
        files={"file": f}, data={"format": "webp"})
open("photo.webp", "wb").write(r.content)

POST/api/v1/image/placeholder

Generate placeholder. Form fields: width height bg_colour text_colour label. No file input needed.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/placeholder \
  -F "width=400" -F "height=300" -F "label=400x300" \
  -o placeholder.png

# Python
import httpx
r = httpx.post("https://utils.bithub.org/api/v1/image/placeholder",
    data={"width": 400, "height": 300, "label": "400x300"})
open("placeholder.png", "wb").write(r.content)

POST/api/v1/image/palette

Extract dominant colour palette. Returns JSON with hex + RGB values.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/palette \
  -F "file=@photo.jpg" -F "count=5"
# → {"palette":[{"hex":"#3a7bd5","rgb":{"r":58,"g":123,"b":213},"percentage":32.1},...]}

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/palette",
        files={"file": f}, data={"count": 5})
print(r.json()["palette"])

POST/api/v1/image/exif-strip

Remove all EXIF metadata (privacy). Returns clean image.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/exif-strip \
  -F "file=@photo.jpg" \
  -o clean.jpg

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/exif-strip",
        files={"file": f})
open("clean.jpg", "wb").write(r.content)

POST/api/v1/image/base64

Encode image to Base64 data URI. Returns JSON { "data_uri": "data:image/png;base64,..." }

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/base64 \
  -F "file=@photo.jpg"
# → {"data_uri":"data:image/jpeg;base64,/9j/4AAQ..."}

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/base64",
        files={"file": f})
print(r.json()["data_uri"][:50])

POST/api/v1/image/watermark

Add text watermark. Form fields: text position opacity font_size colour.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/image/watermark \
  -F "file=@photo.jpg" -F "text=© 2024 Company" -F "position=bottom-right" -F "opacity=0.7" \
  -o watermarked.jpg

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/image/watermark",
        files={"file": f},
        data={"text": "© 2024 Company", "position": "bottom-right", "opacity": 0.7})
open("watermarked.jpg", "wb").write(r.content)

Colour Utilities

POST/api/v1/colour/convert

Convert between HEX, RGB, HSL, HSV. Provide any one as input.

{ "hex": "#ff6600" }
→ { "hex": "#ff6600", "rgb": {"r":255,"g":102,"b":0}, "hsl": {"h":24,"s":100,"l":50}, "css": "rgb(255,102,0)" }

POST/api/v1/colour/name

Find nearest CSS named colour. { "hex": "#ff6347" }{ "name": "tomato", "distance": 0 }

{ "hex": "ff6347" }
→ {"name":"tomato","exact":true,"distance":0,"hex":"#ff6347"}

POST/api/v1/colour/contrast

WCAG contrast ratio. { "hex1": "#000000", "hex2": "#ffffff" } → ratio + AA/AAA pass/fail.

{ "hex1": "000000", "hex2": "ffffff" }
→ {"ratio":21.0,"aa_normal":true,"aa_large":true,"aaa_normal":true,"aaa_large":true}

POST/api/v1/colour/palette

Generate colour scheme. { "hex": "#3b82f6", "scheme": "triadic" }. Schemes: complementary, analogous, triadic, split_complementary, tetradic.

{ "hex": "3b82f6", "scheme": "triadic" }
→ {"colours":["#3b82f6","#f6a83b","#82f63b"],"scheme":"triadic"}

POST/api/v1/colour/mix

Blend two colours. { "hex1": "#ff0000", "hex2": "#0000ff", "weight": 0.5 }#7f007f

{ "hex1": "ff0000", "hex2": "0000ff", "weight": 0.5 }
→ {"result":"#7f007f","rgb":{"r":127,"g":0,"b":127}}

Code Utilities

POST/api/v1/code/highlight

Syntax-highlight code as HTML with embedded CSS. 100+ languages, multiple Pygments themes.

{ "code": "def hello(): print('hi')", "language": "python", "theme": "monokai" }
→ { "html": "<div class=\"highlight\">...</div>", "css": "...", "language": "python" }

POST/api/v1/code/minify

Minify html | css | javascript. Returns minified code + size reduction stats.

{ "code": "  body {  color: red;  }  ", "language": "css" }
→ {"minified":"body{color:red}","original_size":22,"minified_size":14,"reduction_pct":36.4}

POST/api/v1/code/format/sql

Pretty-print SQL. { "sql": "select * from users", "keyword_case": "upper", "indent_width": 2 }

{ "sql": "select id,name from users where active=true", "keyword_case": "upper" }
→ {"formatted":"SELECT id,\n       name\nFROM users\nWHERE active = true"}

POST/api/v1/code/stats

Code statistics — total lines, blank, comments, code lines, byte size. { "code": "...", "language": "python" }

{ "code": "def hello():\n    # greet\n    print('hi')\n", "language": "python" }
→ {"total_lines":3,"code_lines":2,"comment_lines":1,"blank_lines":0,"size_bytes":42}

Diff & Patch

POST/api/v1/diff/text

Generate a diff between two texts. style: unified | context | ndiff | html

{ "original": "foo\nbar", "modified": "foo\nbaz", "style": "unified" }
→ { "diff": "--- original\n+++ modified\n@@...", "added_lines": 1, "deleted_lines": 1, ... }

POST/api/v1/diff/patch

Apply a unified diff patch to original text. { "original": "...", "patch": "---\n+++ ..." }

{ "original": "foo\nbar\nbaz", "patch": "--- a\n+++ b\n@@ -2 +2 @@\n-bar\n+qux" }
→ {"result":"foo\nqux\nbaz","success":true}

POST/api/v1/diff/similarity

Similarity scores 0–100%. Returns char, word, and line similarity. { "text1": "...", "text2": "..." }

{ "text1": "The quick brown fox", "text2": "The quick red fox" }
→ {"char_similarity":88.9,"word_similarity":75.0,"line_similarity":0.0}

POST/api/v1/diff/merge

3-way merge with conflict markers. { "base": "...", "ours": "...", "theirs": "..." }

{ "base": "hello world", "ours": "hello earth", "theirs": "hello globe" }
→ {"result":"<<<<<<< ours\nhello earth\n=======\nhello globe\n>>>>>>> theirs","has_conflicts":true}

PDF Tools

All PDF endpoints accept multipart/form-data. Max file size 20 MB per file.

POST/api/v1/pdf/extract

Extract text from a PDF. Form fields: file + pages (all, 1, 1-3, 1,3,5).

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/pdf/extract \
  -F "file=@document.pdf" -F "pages=1-3"

# Python
import httpx
with open("document.pdf", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/pdf/extract",
        files={"file": f}, data={"pages": "1-3"})
print(r.json()["text"])

POST/api/v1/pdf/metadata

Page count, dimensions, author, title, creator, encryption status.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/pdf/metadata \
  -F "file=@document.pdf"
# → {"title":"My Doc","author":"Alice","pages":12,"created":"2024-01-01"}

# Python
import httpx
with open("document.pdf", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/pdf/metadata",
        files={"file": f})
print(r.json()["pages"])

POST/api/v1/pdf/merge

Merge 2–20 PDFs. Send multiple files fields. Returns binary PDF. Header x-page-count = total pages.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/pdf/merge \
  -F "files=@a.pdf" -F "files=@b.pdf" -o merged.pdf

# Python
import httpx
r = httpx.post("https://utils.bithub.org/api/v1/pdf/merge",
    files=[("files", open("a.pdf","rb")), ("files", open("b.pdf","rb"))])
open("merged.pdf","wb").write(r.content)

POST/api/v1/pdf/split

Extract pages as a new PDF. Form fields: file + pages (e.g. 2-4 or 1,3,5). Returns binary PDF.

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/pdf/split \
  -F "file=@document.pdf" -F "pages=1-3" \
  -o pages.pdf

# Python
import httpx
with open("document.pdf", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/pdf/split",
        files={"file": f}, data={"pages": "1-3"})
open("pages.pdf", "wb").write(r.content)

AI Utilities

Powered by Claude. Requires a valid API key with AI access.

POST/api/v1/ai/summarise

Summarise text. style: bullet | paragraph | one_line

{ "text": "Long article...", "style": "bullet", "max_words": 100 }
→ { "summary": "• Key point 1\n• Key point 2\n...", "word_count": 42 }

POST/api/v1/ai/sentiment

Sentiment analysis. Returns sentiment (positive/negative/neutral/mixed), confidence, reasoning.

{ "text": "I absolutely love this product, it works great!" }
→ {"sentiment":"positive","confidence":0.97,"scores":{"positive":0.97,"neutral":0.02,"negative":0.01}}

POST/api/v1/ai/language

Detect language. Returns ISO 639-1 code, name, confidence, and alternatives.

{ "text": "Bonjour le monde" }
→ {"language":"French","code":"fr","confidence":0.99}

POST/api/v1/ai/alttext

Generate accessible alt text from an image upload (multipart/form-data).

curl / Python
# curl
curl -X POST https://utils.bithub.org/api/v1/ai/alttext \
  -H "X-API-Key: utg_your_key" \
  -F "file=@photo.jpg"
# → {"alt_text":"A golden retriever dog playing in a sunny park with a red ball"}

# Python
import httpx
with open("photo.jpg", "rb") as f:
    r = httpx.post("https://utils.bithub.org/api/v1/ai/alttext",
        headers={"X-API-Key": "utg_your_key"},
        files={"file": f})
print(r.json()["alt_text"])

POST/api/v1/ai/translate

{ "text": "Hello", "target_language": "Spanish", "formality": "formal" }{ "translation": "Hola", "detected_source": "English" }

{ "text": "Hello, world!", "target_language": "Spanish" }
→ {"translated":"¡Hola, mundo!","source_language":"English","target_language":"Spanish"}

POST/api/v1/ai/grammar

Grammar and style check. Returns issues[], style_suggestions[], score, corrected_text.

{ "text": "Their going to the store, its very far." }
→ {"corrected":"They're going to the store; it's very far.","changes":[{"original":"Their","correction":"They're"},{"original":"its","correction":"it's"}]}

Webhooks

Register HTTPS endpoints to receive real-time POST notifications when events occur. Each delivery is signed with HMAC-SHA256 for verification. Requires authentication.

Available Events

url.clicked— short URL was redirected url.created— short URL was created url.deleted— short URL was deleted api_key.created— API key was created rate_limit.hit— API key hit rate limit spend.limit_reached— API key hit spend cap spend.reset— API key spend counter reset

POST/api/v1/webhooks

Register a new webhook. The secret is returned once — store it securely.

// Request
{ "url": "https://your-server.com/webhook", "events": ["url.clicked", "url.created"] }
// Response
{ "id": 1, "url": "...", "events": [...], "secret": "abc123...", "is_active": true, "created_at": "..." }
curl / Python + verification
# Create webhook
curl -X POST https://utils.bithub.org/api/v1/webhooks \
  -H "X-API-Key: utg_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-server.com/hook","events":["url.clicked"]}'

# Verify signature (Python)
import hmac, hashlib
def verify(body: bytes, secret: str, signature_header: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header)

GET/api/v1/webhooks

List all registered webhooks including status, failure count, and last triggered time.

curl -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/webhooks
→ [{"id":"uuid","url":"https://your-server.com/hook","events":["url.clicked"],"active":true,"created_at":"2024-01-01T00:00:00Z"}]

DELETE/api/v1/webhooks/{id}

Delete a webhook and stop all future deliveries.

curl -X DELETE -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/webhooks/uuid
→ {"deleted": true}

GET/api/v1/webhooks/{id}/deliveries

Get last 50 delivery attempts — event, payload, HTTP status, success flag, timestamp.

curl -H "X-API-Key: utg_your_key" https://utils.bithub.org/api/v1/webhooks/uuid/deliveries
→ [{"id":1,"event":"url.clicked","status":200,"delivered_at":"2024-01-01T00:00:00Z","response_ms":45}]

POST/api/v1/webhooks/{id}/deliveries/{delivery_id}/retry

Re-dispatch a previous delivery. Useful for replaying failed events. Returns 202 Accepted.

Delivery payload format

{
  "event": "url.clicked",
  "timestamp": 1709990400,
  "data": { "code": "2BKxmR", "target_url": "https://example.com" }
}

Webhook is auto-disabled after 10 consecutive delivery failures. Re-enable via the dashboard.

OpenAPI Specification

Auto-generated OpenAPI 3.0 spec with full request/response schemas: