Not available
HEIC conversion API (not available)
This API is switched off in production. Every
request to /api/v1/* returns 404,
and no API keys are being issued. It is waiting on a licensing review and may never launch.
The reference below describes how the API would work if it launches: one HTTP request to turn a HEIC/HEIF photo into JPG, PNG, WebP, AVIF, GIF or PDF. The website converter does not use this API — it runs entirely in your browser and works today.
Quickstart
- If the API launches, you would get a key that looks like
hk_live_…, shown to you exactly once. No keys are being issued today; tell us through the feedback form if you would use one. - Export it:
export HEIC_TO_API_KEY=hk_live_… - Send a multipart request with the file:
curl -X POST https://heic-to.io/api/v1/convert \
-H "Authorization: Bearer $HEIC_TO_API_KEY" \
-F "file=@IMG_0001.HEIC" \
-F "format=jpg" \
-F "quality=85" \
-F "max_edge=2048" \
-o IMG_0001.jpg Authentication
Requests would send a key as a Bearer token: Authorization: Bearer hk_live_…. Only a SHA-256 hash of a key would be stored, so a lost key could not be recovered and
would be replaced. Keys would belong on your server, never in a browser or app bundle.
Planned base URL: https://heic-to.io/api/v1, HTTPS only. It returns 404 today.
POST/api/v1/convert
Body: multipart/form-data. On success the response body would be the converted file (status 200). Each successful
conversion would use one unit of a monthly quota; failed requests would not.
| Field | Type | Default | Notes |
|---|---|---|---|
| file | HEIC / HEIF binary | required | The image to convert. Up to 50 MB and 50 megapixels. For multi-image files (bursts, collections) the primary image is converted. |
| format | jpg · png · webp · avif · gif · pdf | jpg | "jpeg" is accepted as an alias for jpg. |
| quality | integer 1–100 | 90 | Encoder quality for jpg, webp, avif and pdf (the embedded JPEG). Ignored for png and gif. |
| max_edge | integer 16–16384 | none | Downscale so the longest side is at most this many pixels, keeping the aspect ratio. Never upscales. |
| keep_metadata | true · false | false | Copy the original EXIF block (camera, date, and GPS location if present) into jpg, png, webp and avif output. By default all metadata is stripped. |
Response headers
- Content-Type
- MIME type of the output, e.g. image/jpeg or application/pdf.
- Content-Disposition
- attachment; filename="<original name>.<ext>"
- X-Image-Width / X-Image-Height
- Pixel size of the output image.
- X-Image-Count
- Number of top-level images in the source file.
- RateLimit-Limit / -Remaining / -Reset
- Per-minute window (IETF draft names).
- X-Quota-Remaining
- Conversions left this calendar month (UTC).
- X-Request-Id
- Quote this when contacting support.
WebP with metadata, saving headers
curl -X POST https://heic-to.io/api/v1/convert \
-H "Authorization: Bearer $HEIC_TO_API_KEY" \
-F "file=@photo.heic" -F "format=webp" -F "keep_metadata=true" \
--fail-with-body -D headers.txt -o photo.webp GET/api/v1/usage
Would report a key’s plan, the current rate-limit window and the month’s quota, counting towards the per-minute limit but not the monthly quota.
curl https://heic-to.io/api/v1/usage \
-H "Authorization: Bearer $HEIC_TO_API_KEY" {
"plan": "free",
"key_prefix": "hk_live_3fA9kQ2z",
"rate_limit": { "per_minute": 10, "remaining": 9, "reset_seconds": 42 },
"quota": {
"month": "2026-09",
"limit": 100,
"used": 17,
"remaining": 83,
"resets_at": "2026-10-01T00:00:00.000Z"
}
} Errors
Every error would have the same JSON shape, so you could branch on error.code and show error.message to
humans.
{
"error": {
"code": "quota_exceeded",
"message": "Monthly quota of 100 conversions used up; it resets at 2026-10-01T00:00:00.000Z."
}
} | Status | code | When |
|---|---|---|
| 400 | invalid_params | A form field is missing or out of range. |
| 401 | invalid_api_key | Missing, malformed, unknown or revoked key. |
| 402 | quota_exceeded | Monthly conversion quota used up. |
| 413 | payload_too_large | File over 50 MB, or image over 50 megapixels. |
| 415 | unsupported_media_type | Body is not multipart/form-data, or the file is not HEIC/HEIF. |
| 422 | unsupported_media_type | Looks like HEIC but could not be decoded (corrupt or unsupported coding). |
| 429 | rate_limited | Per-minute limit hit — honour Retry-After. |
| 500 | internal | Unexpected server error. Safe to retry once. |
| 503 | busy | All conversion workers are busy — retry after Retry-After seconds. |
| 504 | timeout | Conversion took longer than 30 seconds. |
Planned limits
Free
100
conversions / month
10 requests / minute
Pro
10,000
conversions / month
60 requests / minute
Scale
100,000
conversions / month
300 requests / minute
- Max file size 50 MB; max image size 50 megapixels; 30 s per conversion.
- Quotas would reset at 00:00 UTC on the first day of each month.
- On
429or503, clients would wait for theRetry-Afterseconds before retrying. - CORS would be open (no cookies), but keys would belong on your server, not in browsers.
Planned data handling
- Uploaded images would live only in server memory for the duration of the request, and would not be written to disk, cached, logged or used for anything else.
- Only request metadata would be logged: client ID, key prefix, output format, byte sizes, duration, status and, when a request fails, an error code or message — never file names, pixels or EXIF.
- Metadata (including GPS location) would be stripped from output unless you send
keep_metadata=true.
See the privacy policy for details.