Skip to main content

Editing API solution

Edit the picture you already have, not one the model invented.

Editing endpoints take at least two inputs: the image and the instruction. Getting the image in — as a public URL, a committed upload or an inline data URI — is where most integrations stall.

The challenge

Getting the reference in is the hard half

The prompt is the easy part. The other part is a file that lives on your users' phones, has to reach the model without exposing a private bucket, and has to fit limits that are enforced before the task exists.

01

There are three ways in, and they fail differently

A declared image field accepts a public HTTPS URL, a committed spicy:// file URI, or an inline data URI. Inline is capped at 1 MiB decoded and 8,388,608 pixels per image, inside a 2 MiB request body. Anything larger has to go through an upload ticket.

02

Signed HTTPS URLs can work if the file is reachable

A presigned link can reference a private bucket if the URL lets our servers download the file without cookies or a separate login. Keep it valid during processing. Private network addresses, loopback hosts and user:password URL credentials are rejected.

03

Editing is a different task from generation

The public call name ends in /edit, the schema usually requires image_url or image_urls, and some endpoints add mask_url or strength. A text-to-image model value dropped into an edit flow fails validation rather than degrading gracefully.

The approach

Upload once, commit, then reference the file URI

For user files, request an upload ticket, PUT the exact byte count with every returned header, commit, and pass the returned spicy:// URI in the model's image field. The reference then belongs to your account, is checked once, and can be reused across tasks without uploading it again.

Ticket, PUT, commit, create. Media that is already publicly reachable skips the first three steps.

Ticket → PUT → commit → create

POST /api/v1/common/upload-url
{ "contentType": "image/png", "bytes": 482113 }
→ { "fileId": "fil_01k3…", "uploadUrl": "https://…", "method": "PUT", "headers": { … } }

PUT <uploadUrl>            # exactly 482113 bytes, every returned header replayed
POST /api/v1/files/fil_01k3…/commit
→ { "status": "ready", "uri": "spicy://f/fil_01k3…", "sha256": "…" }

POST /api/v1/jobs/createTask

{
  "model": "<publisher>/<model>/edit",
  "input": {
    "prompt": "Replace the background with an overcast beach at dusk",
    "image_urls": ["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]
  }
}

Contract

The parts worth pinning down

Image editing API: edit from a reference image — The parts worth pinning down
Field or headerValue or limit
POST /api/v1/common/upload-urlJPEG · PNG · WebP · GIF ≤ 10 MiB
POST /api/v1/files/{fileId}/commitreturns spicy://f/fil_…
inline data URI≤ 1 MiB decoded · ≤ 8192 px per side
request body≤ 2 MiB · ≤ 16 images

Swipe horizontally to see all columns.

Integration

From first call to production

  1. 01POST /api/v1/common/upload-url with contentType and the exact byte count; images up to 10 MiB as JPEG, PNG, WebP or GIF.
  2. 02PUT the bytes to the presigned URL replaying every header the ticket returned, then POST /api/v1/files/{fileId}/commit.
  3. 03Send createTask with the endpoint's edit model value and the spicy:// URI in image_url or image_urls.
  4. 04Read output.assets from the callback or recordInfo and store the edited file yourself.

Fit

When this path is the right one

Choose this when

  • Your product starts from user photos: retouching, background replacement, restyling, object removal.
  • The same reference is reused across several tasks and should not be uploaded again each time.

Look elsewhere when

  • You have no source image. Text-to-image is the cheaper and simpler contract.
  • You need frame-accurate video edits. Editing endpoints return stills.

Evidence

What you can verify yourself

Uploads are account-bound and checked on commit

Commit compares the stored byte count and media type against the ticket, verifies the image signature and computes a SHA-256 before the file becomes referenceable at all.

Inline images never travel back in the record

Data URIs are stored as account-bound files. The normalized input returned by recordInfo contains file URIs, never the original Base64 bytes.

Source material and results have separate clocks

Material you upload is kept for one day; generated results are kept for 14 days. Both windows are published rather than negotiated per account.

Before launch

Platform behaviour to confirm

  • Decide who confirms rights to the source image; the platform does not inspect it for you.
  • Validate media type and size in your client before asking for a ticket — a 413 is cheaper to avoid than to handle.
  • Keep spicy:// URIs with your own records if the same source will be edited again.
  • Treat invalid_asset as a user-facing error, not an outage.

FAQ

Questions this page gets asked

Either. A publicly reachable HTTPS media URL goes straight into the model's image field. Upload tickets exist for files that are not public, and for anything above the inline limits.