HTTP & cURL
Authentication, errors, and the raw REST flow behind the SDK. Use the HTTP endpoints from any language or from the terminal.
Base URL and authentication
The API base URL is https://api.transform-kit.com. Authenticate every request with a bearer token: an API key created under Credentials, a CLI login key, or an OAuth-minted token.
export API_KEY=tk_your_key_here
export TK_API=https://api.transform-kit.com
# Every call carries the bearer header:
# Authorization: Bearer $API_KEYKeys are secrets
Anyone with a key can access the account and run transforms. Keep keys in server-side environment variables. Revoke a leaked key under Credentials. For a local API over portless TLS, pointTK_API at that origin and pass --cacert ~/.portless/ca.pem to curl if needed.Pipeline request flow
Five steps: mint an upload URL → PUT the bytes → submit the pipeline → poll → fetch the result.
1. Create an upload URL
curl -s -X POST "$TK_API/v1/uploads" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"content_type":"image/jpeg"}'{
"upload_url": "https://…presigned-put…",
"input_key": "inputs/<user>/<uuid>",
"expires_in": 3600,
"content_type": "image/jpeg"
}2. Upload the file
PUT the file straight to the presigned URL. No API auth here: the URL is the credential.
curl -s -X PUT "<upload_url>" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg3. Submit a pipeline
Post a { nodes, edges } graph. Returns 202 with one job per pipeline.output. Build and validate the graph under Pipelines.
curl -s -X POST "$TK_API/v1/pipelines" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_key": "inputs/<user>/<uuid>",
"content_type": "image/jpeg",
"filename": "photo.jpg",
"pipeline": {
"nodes": [
{ "id": "in", "type": "pipeline.input" },
{ "id": "resize", "type": "image.resize",
"config": { "mode": { "value": "pixels" },
"width": { "value": 1600 }, "height": { "value": 1600 },
"fit": { "value": "inside" } } },
{ "id": "convert", "type": "image.convert",
"config": { "format": { "value": "webp" }, "quality": { "value": 82 } } },
{ "id": "out", "type": "pipeline.output" }
],
"edges": [
{ "source": "in", "target": "resize" },
{ "source": "resize", "target": "convert" },
{ "source": "convert", "target": "out" }
]
}
}'{ "jobs": [ { "job_id": "<uuid>", "output": "out" } ] }Body fields: input_key (from step 1) or a BYOS input_url; pipeline (required { nodes, edges }); optional content_type, filename, and output_targets (BYOS delivery, see below). Add more pipeline.output nodes to fan out, one job each.
Node types, one media family per graph: pipeline.input,pipeline.output,image.resize,image.filter,image.convert,video.resize,video.filter,video.convert,audio.filter,audio.convert,document.filter,document.convert. Fields and defaults are in the pipeline node reference.
4. Poll the job
curl -s "$TK_API/v1/jobs/<job_id>" \
-H "Authorization: Bearer $API_KEY"{
"job_id": "<uuid>",
"kind": "image.pipeline",
"status": "succeeded",
"state": "success",
"created_at": "2026-07-26T00:00:00.000Z",
"completed_at": "2026-07-26T00:00:02.000Z",
"expires_at": "2026-07-27T00:00:00.000Z",
"retryable": false
}Poll until status is succeeded or failed. This endpoint returns the current job state. kind names the media the graph operates on: image.pipeline, video.pipeline, audio.pipeline or document.pipeline.
5. Retrieve the result
curl -s "$TK_API/v1/jobs/<job_id>/result" \
-H "Authorization: Bearer $API_KEY"{
"media": {
"url": "https://…signed-get…",
"expires_in": 86400,
"content_type": "image/webp",
"format": "webp",
"width": 1600,
"height": 1067,
"file_size": 184320
}
}The envelope is always media, same shape for every medium. Dimensions are present when the transport reports them (images and video); audio and documents omit them.
Bring your own storage
Skip TransformKit's bucket entirely. Pass an HTTPS input_url the worker can GET, and/or an output_targets array with a presigned PUT per output. The SDK's .upload() / .deliver() hooks build this body for you.
curl -s -X POST "$TK_API/v1/pipelines" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_url": "https://your-bucket.example/inputs/photo.jpg?<signed-get>",
"content_type": "image/jpeg",
"filename": "photo.jpg",
"pipeline": { "nodes": [/* … */], "edges": [/* … */] },
"output_targets": [
{
"output_id": "out",
"key": "outputs/<user>/<uuid>.webp",
"put_url": "https://your-bucket.example/outputs/photo.webp?<signed-put>",
"content_type": "image/webp",
"public_url": "https://cdn.example/photo.webp"
}
]
}'input_url and each put_url / public_url must be HTTPS. The worker fetches and delivers under SSRF constraints. Presigned URLs are short-lived. A retry reuses the same URLs, so sign them long enough for a retry window or treat BYOS as fire-once.Identity & health
# Who am I?
curl -s "$TK_API/v1/me" -H "Authorization: Bearer $API_KEY"
# Is the API up? (no auth)
curl -s "$TK_API/health"Result retention
Inputs and outputs are deleted about 24 hours after job creation, and signed result URLs expire with them. Copy anything you need to keep to your own storage.
Status codes
202, job accepted (submit).400, bad request, e.g.missing_input,invalid_input_key,invalid_pipeline.401,missing_api_keyorinvalid_api_key.409,job_not_ready(result requested before the job finished).410,result_expired(past the 24h window).422,job_failed.429,rate_limited(short-burst limit).