Images
How to send images to the ReWords.AI API — URL, base64, data URL or multipart upload — the size and format limits, EXIF and transparency handling, the result files, and how boxes map to pixels.
What you can send
| Limit | |
|---|---|
| Formats | JPEG, PNG, WebP. Detected from the file's bytes, not its name or Content-Type. |
| File size | Up to 20 MB (20 × 1024 × 1024 bytes; the 28 MB JSON body limit is counted the same way). |
| Dimensions | Longest side up to 8000 px; shortest side at least 32 px. |
| Colour | RGB or greyscale. CMYK JPEGs are rejected with 400 invalid_image. |
| Animation | Animated WebP: only the first frame is used. |
A file that breaks these rules is rejected with 400 invalid_image before anything is charged.
Four ways to send an image
Use exactly one per request. Sending none, or more than one, returns 400 invalid_request.
1. image_url
A public http(s) link. We download it once, while handling your request, so a signed link only has to stay valid
until we answer. We follow up to 3 redirects and give up after 15 seconds; if the file cannot be downloaded the request
returns 400 invalid_image. Links that need cookies or a login do not work, and neither do addresses on a private
network, such as localhost, 10.x.x.x or 192.168.x.x.
{ "image_url": "https://example.com/banner.png" }2. image_base64
The file's bytes in standard base64 (A–Z a–z 0–9 + /, padding optional), or the same as a data URL with any media
type, such as data:image/png;base64, or the data:application/octet-stream;base64, a browser's FileReader may
produce — the format is detected from the bytes. Spaces and line breaks are ignored, so the 76-character lines of
base64 on Linux or Python's base64.encodebytes work. Base64 makes the file about a third larger, so the whole JSON
body may be up to 28 MB; a larger body returns 400 invalid_image. Text that is not valid base64 returns
400 invalid_request; valid base64 of a file that is not a supported image returns 400 invalid_image.
{ "image_base64": "iVBORw0KGgoAAAANSUhEUgAA..." }
{ "image_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." }3. multipart file upload
Send multipart/form-data with the file in the image field. For POST /edits, put the replacements array in a
form field as a JSON string; match, language and callback_url are plain form fields.
curl https://api.rewords.ai/v1/edits \
-H "Authorization: Bearer $REWORDS_API_KEY" \
-F image=@banner.png \
-F 'replacements=[{"from":"SALE","to":"HOT DEAL"}]'import crypto from 'node:crypto';
import fs from 'node:fs';
const form = new FormData();
form.append('image', new Blob([await fs.promises.readFile('banner.png')]), 'banner.png');
form.append('replacements', JSON.stringify([{ from: 'SALE', to: 'HOT DEAL' }]));
const res = await fetch('https://api.rewords.ai/v1/edits', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.REWORDS_API_KEY}`, // let fetch set the multipart Content-Type
'Idempotency-Key': crypto.randomUUID(), // a new key per job; reuse it only to resend this same job
},
body: form,
});
const job = await res.json();
if (!res.ok) throw new Error(`${res.status} ${job.error.code}: ${job.error.message}`);
console.log(job.id, job.status);4. image_id
POST /ocr returns an image_id. Pass it to POST /edits within 24 hours to reuse the uploaded image instead of
sending it again. It only works on the account that created it; an unknown, expired or other account's id returns
400 invalid_request. Each OCR call returns a new image_id, even for an image you sent before — including when you
send an image_id to POST /ocr, which gives you a fresh 24 hours.
How we read your image
- EXIF orientation is applied first. A phone photo stored sideways is turned upright, and every
width,heightand box refers to the upright image — what you see in an image viewer. - Transparent areas become white. PNG and WebP transparency is flattened onto a white background, because results are JPEG.
Results
results.A.url,results.B.urlandresults.C.urlare JPEG files at public links: download them with a plainGET, no API key needed. Treat the links as private — anyone who has one can open it.- Send a
User-Agentheader when you download. Pythonurllib's default one is refused with403;requests,curl, browsers and Nodefetchwork as they are. - Links are kept for at least 7 days. Download what you need to keep.
- Result files are stored upright with no EXIF orientation, so the size in the file is the size you see.
- B is your original image with the new text blended in. A is the AI's redraw of the whole image and keeps your image's aspect ratio. Read the pixel size from the file rather than assuming it matches your upload.
- C (4K) is up to about 8.3 megapixels (3840 × 2160 worth), longest side at most 3840 px, same aspect ratio. It is skipped for images wider or taller than 3:1.
Boxes and pixels
Boxes are [x, y, width, height], whole numbers on a 0–1000 scale of the upright image, measured from the top-left
corner. width and height are at least 1; x + width and y + height are never more than 1000.
pixel left = x / 1000 * imageWidth
pixel top = y / 1000 * imageHeight
pixel width = width / 1000 * imageWidth
pixel height = height / 1000 * imageHeightExample: box [120, 80, 300, 60] on a 1080 × 1350 image is left 130, top 108, 324 × 81 px (rounded).
To send your own box, convert the other way and round to whole numbers.