Image Editor API
REST API reference for the Image Editor. For the product overview and UI walkthrough, see Image Editor.
The Image Editor is available via the Flokan public API, so you can run prompt-based image generation and edits from your own scripts, n8n flows, or any HTTP client. The API is synchronous: POST /process keeps the connection open until the provider returns the finished image.
Authentication
All requests require a workspace API key minted in Workspace Settings → API Keys. Pass the key in the Authorization header:
Authorization: Bearer flk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThe key must include the image_editor scope, and the user who created the key must have the Access Image Editor permission in the workspace.
Base URL
https://app.flokan.com/api/v1/image-editorChoosing a source image
POST /process accepts three input modes — pick whichever fits your pipeline:
- Text-to-image — omit both
image_idandimage_url. The prompt alone drives generation. - Edit a Flokan-hosted image — first call
POST /upload-url, PUT the file to the returnedupload_url, then pass the returnedimage_idtoPOST /process. - Edit an external image — pass
image_url(HTTPS) directly. The server fetches the image and uses it as the source.
image_id takes precedence over image_url if both are sent.
Endpoints
POST /upload-url — Generate a presigned upload URL
Returns a short-lived PUT URL plus the image_id you'll pass to /process.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
file_name | string | yes | 1–255 characters |
mime_type | string | yes | One of image/jpeg, image/png, image/webp, image/gif |
file_size | integer | no | Bytes — record-keeping only |
Response 201
{
"success": true,
"data": {
"image_id": "f24a8c52-...",
"upload_url": "https://...presigned PUT URL...",
"public_url": "https://images.flokan.com/...",
"expires_in": 3600
}
}PUT the file bytes to upload_url with the same Content-Type you declared as mime_type. The presigned URL expires after expires_in seconds (one hour).
POST /process — Generate or edit an image (synchronous)
The call returns once generation finishes (typically 10–60 seconds depending on model and provider). The Vercel max duration is 300 seconds.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
prompt | string | yes | 1–10000 characters |
model_tier | string | yes | pro, standard, or creative |
image_id | uuid | no | Source image previously created via /upload-url. Must belong to this workspace. |
image_url | string | no | HTTPS URL the server fetches as the source image. Ignored if image_id is set. Max 2000 characters. |
style_id | uuid | no | Apply a saved style preset (workspace-scoped or system) |
character_id | uuid | no | Apply a saved character preset for figure consistency |
provider | string | no | Routes the call. Default "platform" (Flokan system keys, deducts credits). Set to "openai", "google", "fal", or "kie" to use the workspace's configured BYOK key for that provider — no credits are deducted. Strict: errors 422 if the workspace doesn't have that BYOK provider configured + enabled, or if the workspace's plan doesn't include BYOK. |
BYOK + model tier compatibility
When provider is set to a BYOK provider, only certain model_tier values are accepted:
| Provider | Allowed model_tier |
|---|---|
openai | pro, standard |
google | pro |
fal | pro, standard, creative |
kie | pro, standard, creative |
Passing an unsupported combination returns 400.
Response 201
{
"success": true,
"data": {
"job_id": "9c0d4f31-...",
"status": "completed",
"result_url": "https://images.flokan.com/USER_ID/processed/JOB_ID.png",
"result_image_id": "ab7e2511-...",
"model_tier": "pro",
"provider_used": "system",
"credits_consumed": 50,
"processing_ms": 18432,
"created_at": "2026-05-04T11:00:00.000Z",
"completed_at": "2026-05-04T11:00:18.432Z"
}
}result_image_id can be passed back as image_id on a follow-up /process call to chain edits — useful for iterative refinement workflows. provider_used is "system" for platform calls and the BYOK provider name otherwise. credits_consumed is 0 for BYOK calls.
POST /estimate-credits — Predict cost before calling /process
Returns a per-call upper-bound estimate plus the workspace's available credits and a can_proceed flag. Mirrors the BYOK rules of /process, so the estimate doesn't lie when you switch providers.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
model_tier | string | yes | pro, standard, or creative |
provider | string | no | Same values as /process. Default "platform". |
Response 200
{
"success": true,
"data": {
"model_tier": "pro",
"provider": "platform",
"estimated_credits": 50,
"is_exact": false,
"available_credits": 12450,
"can_proceed": true,
"byok_skips_credits": false
}
}The estimate is an upper bound — the post-call deduction (visible on /process's response and on the job row) is the source of truth. BYOK providers always return estimated_credits: 0 and byok_skips_credits: true.
GET /jobs — List jobs
Query params
| Param | Type | Notes |
|---|---|---|
page | integer | Default 1 |
per_page | integer | Default 50, max 100 |
status | string | pending, processing, completed, or failed |
Returns the most recent jobs first.
GET /jobs/:jobId — Fetch one job
Returns the job's full row, including result_url, processing_ms, error (when failed), and the resolved style_id / image_id. Useful for historical lookups even though /process itself is synchronous.
Errors
All error responses use the envelope { "success": false, "error": "..." }. Common status codes:
| Code | Meaning |
|---|---|
400 | Validation error (bad model tier, bad provider, BYOK matrix mismatch, …) |
401 | Missing or invalid API key |
402 | Insufficient AI credits |
403 | Missing image_editor scope or access_image_editor permission |
404 | image_id, style_id, character_id, or jobId not found in this workspace |
422 | Provider safety filter rejected the prompt, or BYOK provider is not configured + enabled on the workspace |
429 | Rate limit exceeded (Flokan or provider). See Retry-After and X-RateLimit-* headers. |
500 | Unexpected server or provider error |
Rate limits
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. The per-minute limit is determined by the workspace's billing plan.