Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.handtextai.com/llms.txt

Use this file to discover all available pages before exploring further.

1) Get an API key

Create an API key in the HandTextAI dashboard and copy the value (it starts with htext_).

2) Generate a PNG

For the most predictable production output, start with font_id: 1 or 2 and validate your final settings with /preview before you ship.
curl -sS https://api.handtextai.com/api/v1/generate \
  -H "Authorization: Bearer htext_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Hello from HandTextAI!",
    "font_id": 1,
    "font_size": "auto",
    "page_size": "a4",
    "dpi": 300
  }' \
  | python3 - <<'PY'
import sys, json, base64
payload = json.load(sys.stdin)
img = base64.b64decode(payload["image_base64"])
open("output.png", "wb").write(img)
print("Saved output.png (request_id:", payload.get("request_id"), ")")
PY

3) Preview before you generate (free)

Use /preview to iterate on margins/font sizing quickly. Previews are watermarked and free.
curl -sS https://api.handtextai.com/api/v1/preview \
  -H "Authorization: Bearer htext_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello!", "font_id": 1, "font_size": "auto", "page_size": "a4"}'

4) Generate a PDF

PDF responses are binary, not JSON.
curl -sS https://api.handtextai.com/api/v1/generate \
  -H "Authorization: Bearer htext_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Hello from HandTextAI!",
    "font_id": 1,
    "font_size": "auto",
    "page_size": "letter",
    "output_format": "pdf"
  }' \
  -o output.pdf

5) Handle rate limits

When you hit rate limits, use the Retry-After header:
import time

def generate_with_retry(request_data, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(
            "https://api.handtextai.com/api/v1/generate",
            headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
            json=request_data,
        )

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            print(f"Rate limited, waiting {retry_after}s...")
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")

Need to generate many outputs?

Use the dashboard’s Batch Generation for CSV-based bulk processing.

Troubleshooting

ErrorCauseSolution
401Invalid API keyCheck Authorization: Bearer htext_... format
422Validation errorCheck details array in response for field errors
429Rate/quota limitWait for Retry-After seconds, then retry
See Errors & Rate Limits for complete error reference.