DEVELOPERS
Make It Say API: change the text in images from code
Send an image and the lines to change; get back a PNG with the new text in the same lettering. Base URL https://makeitsay.com/api/v1. Every request needs Authorization: Bearer mis_YOUR_KEY.
Get a key
Sign in, confirm your email address, and create a key on API keys. The key is shown once. Keep it out of shared code; anyone with it can spend the credits on your account. Revoke it there if it leaks.
POST /edits
Change the text in an image. JSON with image_url or image_base64 and replacements, or multipart with a file field and replacements as a JSON string. Optional hint says where the text is when it appears twice. Returns 202 with the edit. Add an Idempotency-Key header to retry safely: the same key returns the same edit and is not scanned or charged again.
curl https://makeitsay.com/api/v1/edits \
-H "Authorization: Bearer $MAKEITSAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: menu-001" \
-d '{ "image_url": "https://example.com/menu.jpg", "replacements": [ { "from": "$12", "to": "$14" }, { "from": "Tuesday", "to": "Wednesday" } ] }'Response:
{
"id": "2kFq…",
"status": "working",
"credits": 1,
"changes": [
{ "from": "$12", "to": "$14", "box": [412, 188, 498, 231] },
{ "from": "Tuesday", "to": "Wednesday", "box": [120, 540, 380, 590] }
],
"result_url": null
}GET /edits/{id}
The edit. status is working, ready or failed (the credit is returned). When ready, result_url is the edited PNG, valid for one hour.
curl https://makeitsay.com/api/v1/edits/2kFq… \
-H "Authorization: Bearer $MAKEITSAY_API_KEY"Response:
{
"id": "2kFq…",
"status": "ready",
"result_url": "https://…/results/2kFq….png?X-Amz-Signature=…",
"result_url_expires_at": "2026-10-24T13:00:00.000Z"
}POST /scans
Read the text without editing: every line with its box (0 to 1000 from the top left). Free; counts toward the scan limit.
curl https://makeitsay.com/api/v1/scans \
-H "Authorization: Bearer $MAKEITSAY_API_KEY" \
-F file=@menu.jpgResponse:
{
"lines": [{ "text": "Lunch special $12", "box": [80, 180, 500, 235] }],
"width": 1200,
"height": 1600
}GET /credits
Credits available on the account.
curl https://makeitsay.com/api/v1/credits \
-H "Authorization: Bearer $MAKEITSAY_API_KEY"Response:
{ "credits": 40 }Errors
Errors are JSON: { "error": "code", "message": "…" }
| Status | error | Meaning |
|---|---|---|
| 401 | unauthorized | Missing, wrong or revoked key. |
| 402 | insufficient_credits | No credits left. |
| 400 | text_not_found | A "from" text is not in the image. The response has missing and lines. |
| 400 | invalid_request, invalid_replacements | The body is not what the endpoint expects. |
| 400 | image_fetch_failed | image_url could not be downloaded over https within 10 seconds. |
| 400, 413, 415 | bad_image | Not a PNG or JPG, or outside the size limits. |
| 422 | document | An ID or official document; refused, nothing charged. |
| 404 | not_found | No edit with this id on this account. |
| 429 | rate_limited, quota, too_many | Over 120 requests a minute for this key, over the scan limit, or three edits already running. |
| 503 | not_open, busy | The API or scanning is switched off for now. |
Using Claude Code, Cursor or Codex? Connect over MCP →
Credits and limits
- Same credits as the website: 1 credit per image, however many lines you change. Failed edits are not charged.
- Images: PNG or JPG, 64 to 4096 pixels a side, up to 8.4 megapixels and 10 MB. Send a file, a public https URL, or base64.
- Up to 20 lines per image, each up to 200 characters. "from" is the text as it appears in the image; an empty "to" removes the line.
- The image is scanned first. If a "from" text is not in the image, nothing is charged and the response lists the lines that were read.
- IDs, passports, licences, certificates, transcripts, receipts, invoices and bank documents are refused.
- Scans count toward 30 an hour and 100 a day per account. Three edits can run at once.
- The result is a PNG at the size of the original. Its URL works for one hour; get the edit again for a fresh one. The original and the result are kept 30 days, then deleted.
- Each key allows 120 requests a minute. Keys are shown once; you can have 5 active keys.