POST /v1/transform
Image Transform API
Resize, crop, rotate, flip, trim, pad, deskew, and adjust image geometry.
Opérations clés
resize
crop
rotate
flip
mirror
deskew
straighten
trim
pad
extend_canvas
change_dimensions
Cas d’utilisation
Responsive asset generation
Thumbnail pipelines
Image normalization for ML inputs
Cycle de vie de la tâche async
Tous les endpoints de traitement ImageHQ sont asynchrones. Après un POST réussi, vous recevez une réponse 202 Acceptedavec un job_id. Interrogez l’endpoint de statut jusqu’à ce que l’état atteigne succeeded.
Exemple de requête
import requests
url = "https://api.imagehq.io/v1/transform"
payload = {
"operations": [
{
"mode": "fit",
"type": "resize",
"width": 1200
}
],
"output_format": "same_as_input",
"tool_slug": "resize-image"
}
files = [("files[]", open("image.png", "rb"))]
data = {"request": json.dumps(payload)}
response = requests.post(url, files=files, data=data)
print(response.json())const form = new FormData();
form.append("files[]", file);
form.append("request", JSON.stringify({
"operations": [
{
"mode": "fit",
"type": "resize",
"width": 1200
}
],
"output_format": "same_as_input",
"tool_slug": "resize-image"
}));
const response = await fetch("https://api.imagehq.io/v1/transform", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: form
});
const data = await response.json();
console.log(data);const form = new FormData();
form.append("files[]", file);
form.append("request", JSON.stringify({
"operations": [
{
"mode": "fit",
"type": "resize",
"width": 1200
}
],
"output_format": "same_as_input",
"tool_slug": "resize-image"
}));
const response = await fetch("https://api.imagehq.io/v1/transform", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: form
});
const data = await response.json();
console.log(data);curl -X POST "https://api.imagehq.io/v1/transform" \
-H "Idempotency-Key: $(uuidgen)" \
-F "files[]=@image.png" \
-F 'request={"operations":[{"mode":"fit","type":"resize","width":1200}],"output_format":"same_as_input","tool_slug":"resize-image"}'$client = new GuzzleHttp\Client();
$response = $client->post("https://api.imagehq.io/v1/transform", [
"multipart" => [
["name" => "files[]", "contents" => fopen("image.png", "r")],
["name" => "request", "contents" => '{"operations":[{"mode":"fit","type":"resize","width":1200}],"output_format":"same_as_input","tool_slug":"resize-image"}']
]
]);require "faraday"
response = Faraday.post("https://api.imagehq.io/v1/transform") do |req|
req.headers["Idempotency-Key"] = SecureRandom.uuid
req.body = { "files[]" => Faraday::UploadIO.new("image.png", "image/png"), "request" => '{"operations":[{"mode":"fit","type":"resize","width":1200}],"output_format":"same_as_input","tool_slug":"resize-image"}' }
endbody := &bytes.Buffer{}
writer := multipart.NewWriter(body)
writer.WriteField("request", `{"operations":[{"mode":"fit","type":"resize","width":1200}],"output_format":"same_as_input","tool_slug":"resize-image"}`)
file, _ := writer.CreateFormFile("files[]", "image.png")
_ = file
writer.Close()
http.Post("https://api.imagehq.io/v1/transform", writer.FormDataContentType(), body)HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.imagehq.io/v1/transform"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.POST(HttpRequest.BodyPublishers.ofString("multipart form data"))
.build();using var form = new MultipartFormDataContent();
form.Add(new StringContent('{"operations":[{"mode":"fit","type":"resize","width":1200}],"output_format":"same_as_input","tool_slug":"resize-image"}'), "request");
form.Add(new StreamContent(File.OpenRead("image.png")), "files[]", "image.png");
await httpClient.PostAsync("https://api.imagehq.io/v1/transform", form);var request = URLRequest(url: URL(string: "https://api.imagehq.io/v1/transform")!) request.httpMethod = "POST" request.setValue(UUID().uuidString, forHTTPHeaderField: "Idempotency-Key") // Attach multipart files[] and request fields before sending.
Réponse réussie
{
"completed": {
"download_url": "/v1/jobs/job_123/download",
"expires_at": "2026-05-03T00:00:00Z",
"id": "job_123",
"inputs": [
{
"filename": "input.png",
"format": "png",
"mime_type": "image/png",
"size_bytes": 420122
}
],
"outputs": [
{
"filename": "output.jpg",
"format": "jpg",
"id": "0",
"mime_type": "image/jpeg",
"size_bytes": 161002
}
],
"progress": 100,
"retention_policy": {
"clamp": true,
"ttl_hours": 24
},
"stages": [
{
"name": "queued",
"progress": 100,
"status": "succeeded"
},
{
"name": "processing",
"progress": 100,
"status": "succeeded"
}
],
"status": "succeeded",
"warnings": []
},
"queued": {
"client_reference_id": "example-123",
"created_at": "2026-05-02T00:00:00Z",
"current_stage": "queued",
"expires_at": "2026-05-03T00:00:00Z",
"id": "job_123",
"operation": "transform",
"poll_url": "/v1/jobs/job_123",
"progress": 0,
"status": "queued",
"tool_slug": "png-to-jpg"
}
}Questions fréquentes
Can I chain multiple transforms?
Yes. Transform requests support ordered operations in one job.
How are invalid coordinates handled?
The backend validates operation payloads before queueing a job.
Can transform keep original format?
Use output_format as same_as_input to preserve source format where possible.