CursiveToText API documentation
Send an image of handwriting, cursive or printed text and get the recognized text back as JSON. One endpoint, one API key, predictable per-image pricing.
https://www.cursivetotext.com/api/v1Overview
The API is a small REST interface over the same recognition engine that powers the cursive to text converter. It accepts JPEG, PNG, GIF and WebP images up to 10 MB and returns UTF-8 text with line breaks preserved, a confidence score from 0–100 and your remaining allowance.
- All requests use HTTPS. Plain HTTP is not supported.
- Responses are JSON. Every response includes an
X-Request-Idheader you can quote to support. - Images are processed in memory and never stored. Recognized text is returned to you and not kept on our servers.
Authentication
Create a key on the API keys page (sign-in required) and send it in the Authorization header:
Authorization: Bearer ctt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeys are shown once when created and stored only as a one-way hash, so we can’t recover a lost key — create a new one and revoke the old. You can have up to five active keys. Keep keys on your server: never ship them in browser JavaScript or mobile apps.
Quick start
- Sign in and create a key on the API keys page.
- Save it as an environment variable, for example
CURSIVETOTEXT_API_KEY. - Send your first image:
curl https://www.cursivetotext.com/api/v1/recognize \
-H "Authorization: Bearer $CURSIVETOTEXT_API_KEY" \
-F "image=@letter.jpg"Recognize text
POST/api/v1/recognize
Recognizes the text in one image. Each successful call uses one call from your API quota. Calls that fail or find no text are not charged.
Request body
Send the image in either of two ways:
| Content type | Field | Description |
|---|---|---|
multipart/form-data | image (file) | Recommended. The raw image file, up to 10 MB. |
application/json | image (string) | Base64-encoded image, with or without a data:image/…;base64, prefix. Base64 adds about 33%, so keep source images under ~7 MB. |
curl https://www.cursivetotext.com/api/v1/recognize \
-H "Authorization: Bearer $CURSIVETOTEXT_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"image\": \"$(base64 < letter.jpg | tr -d '\n')\"}"Response
| Field | Type | Description |
|---|---|---|
id | string | Unique ID for this recognition. |
object | string | Always "recognition". |
text | string | Recognized text. Lines are separated by \n. |
confidence | integer | Average word confidence, 0–100. Below ~70 usually means the image needs a closer look. |
word_count | integer | Number of words detected. |
processing_ms | integer | Recognition time in milliseconds. |
usage | object | Your allowance after this call: plan, limit, used, remaining, resets_at. |
{
"id": "rec_4f1c9a2e7b3d40c8a6e1",
"object": "recognition",
"text": "Dear Anna,\nLife is a beautiful journey —\nkeep writing your story.",
"confidence": 94,
"word_count": 11,
"processing_ms": 1180,
"usage": {
"plan": "API Growth",
"limit": 5000,
"used": 1242,
"remaining": 3758,
"resets_at": "2026-11-22T13:32:01.000Z"
}
}Check usage
GET/api/v1/usage
Returns your current allowance without using a conversion — handy for dashboards and for checking quota before a batch job.
curl https://www.cursivetotext.com/api/v1/usage -H "Authorization: Bearer $CURSIVETOTEXT_API_KEY"
{ "object": "usage", "plan": "API Growth", "limit": 5000, "used": 1242, "remaining": 3758, "resets_at": "2026-11-22T13:32:01.000Z" }Errors
Errors use standard HTTP status codes and a JSON body with a stable, machine-readable code:
{
"error": {
"code": "quota_exceeded",
"message": "Your API calls for this period are used up. …",
"request_id": "req_9b2d71c0e4a84f5e93aa"
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | image_missing | No image was sent, or it was empty. |
| 400 | invalid_image | The "image" field is not valid base64. |
| 400 | unsupported_image_type | The file is not a JPEG, PNG, GIF or WebP image. |
| 401 | missing_api_key | No API key was sent. |
| 401 | invalid_api_key | The key is wrong or has been revoked. |
| 402 | quota_exceeded | Your API calls for this period are used up. |
| 404 | not_found | Unknown endpoint. |
| 405 | method_not_allowed | Wrong HTTP method for this endpoint. |
| 413 | image_too_large | The image is larger than 10 MB. |
| 415 | unsupported_content_type | Use application/json or multipart/form-data. |
| 422 | no_text_found | No text was detected. The call is not charged. |
| 429 | rate_limited | More than 60 requests in a minute on one key. |
| 503 | service_unavailable | Temporary problem on our side. Retry with backoff. |
Retry 429 and 503 with exponential backoff. Do not retry 4xx errors without changing the request.
Limits
- Formats: JPEG, PNG, GIF, WebP. To convert a PDF, export each page as an image first.
- Size: up to 10 MB per image (about 7 MB when sent as base64).
- Rate: 60 requests per minute per key. Need more? Contact us.
- Timeout: most images finish in 1–3 seconds; allow up to 60 seconds in your HTTP client.
- Languages: tuned for English handwriting and cursive; printed text in most Latin-script languages is also recognized.
Pricing & quotas
The API has its own plans and quota, separate from website conversion plans. Every account includes 25 free API calls per month for testing. API plans add a monthly allowance:
| Plan | Calls | Price (US) | Per call |
|---|---|---|---|
| API Free | 25 / month | $0 | — |
| API Starter | 1,000 / month | $19 / month | 1.9¢ |
| API Growth | 5,000 / month | $49 / month | ~0.98¢ |
| API Scale | 20,000 / month | $149 / month | ~0.75¢ |
Choose or change a plan on the API keys page. Local prices apply in many countries — see pricing. For more than 20,000 calls a month, a higher rate limit or invoiced billing, see business plans.
Best practices
- Image quality matters most. Even lighting, dark ink, the page filling the frame and 1,500px+ on the long side give the best results.
- One page per call. Crop multi-page photos and send pages separately.
- Use the confidence score. Route low-confidence results to a human review step.
- Keep keys server-side and rotate them if they may have been exposed.
- Handle 402 by prompting for an upgrade or pausing the job until
resets_at.
Changelog
- v1 released:
POST /recognize,GET /usage, multipart and base64 uploads.