Skip to main content

AI image and video storage: temporary upload URLs, short-lived results, and a reliable API handoff

What SpicyAPI keeps and for how long: 1-day uploads, 14-day results, 20-minute links, and the settings and API calls that shorten or destroy it.

Author
SpicyAPI Engineering
Published
Read
12 min read
Updated
Landscape cards linked by golden light from a glass bowl through a shielded bell jar to a glass display frame

If you are building an uncensored AI image or video product, three facts decide your storage design. Uploaded reference files last 1 day. Generated media from API, SDK and Playground tasks lasts about 14 days (Studio short-film media has a separate cap of about 60 days), and every download link you are handed works for only about 20 minutes. All of these are caps: you can only shorten them, either for the whole account or for one request, and you can destroy a finished task's content on demand. Nothing you set makes them longer.

So the dependable pattern is: upload directly with a short-lived ticket, commit the file, submit an asynchronous task with the private spicy:// reference, collect the result link when the task finishes, and either copy the result to storage you control or let it expire on purpose. Do not put a customer's upload in a public bucket, and do not save a returned download URL as if it were permanent.

Uploading a reference to SpicyAPI is free; the generation task that uses it is charged separately. Refreshing an existing result's download link does not run or buy the generation again. Creating a new generation attempt has its own model charge, while the storage, requests and transfer for a copy in your own bucket follow your storage provider's pricing.

Read the accepted retention deadlines before promising a storage window to customers; the retention documentation explains the settings. A practical local-copy example is in turning temporary AI media into durable product assets.

Try it in the Playground first

  1. Open the z-image text-to-image page, stay on Workbench in Form, type a Prompt, choose an Aspect ratio and select Run model (sign in first; this one image is a normal paid generation). Check it under Preview and save it with Download.
  2. In the Console, open Logs and find that task to see how long its output is kept.
  3. Open Data protection, then Retention, to see the four clocks and shorten any of them.
  4. Once you have your own copy, select Destroy outputs on the finished task to delete its content.

What SpicyAPI keeps, and for how long

DataKept forWhat happens at expiry
Reference files you upload1 day after a successful commitThe spicy:// URI stops working for new tasks (including retries); the object is then deleted, with cleanup lagging by up to 24 hours
Generated image, video and audioAbout 14 days for API, SDK and Playground results; about 60 days inside a Spicy Studio short-film project, with up to 24 hours of cleanup lagDeleted from object storage; no download link can be issued
Prompt text and result file paths on the task (input, output)30 daysBoth fields are cleared; the task row stays
Task record (ID, model, state, amount, timestamps)IndefinitelyKept as billing evidence; content fields are cleared on their own schedule
Billing ledgerAs long as US tax and accounting law requires (a period measured in years)Kept; unaffected by deleting content
Task logs and webhook delivery recordsAt least 60 daysDeleted
Database backups35 daysRoll over; deleting content does not erase backups instantly

Shorten it, or destroy it, yourself

1. Account retention clocks. Under Retention on the console's Data protection page there are four separate clocks:

ClockCoversDefaultShorter options
Generated resultsImages, video, audio and the result payloadAbout 14 days1 hour, 6 hours, 24 hours, 7 days
Short-film mediaStudio short-film media and exported filmsAbout 60 days1 hour up to 30 days
Prompt textThe text fields of the request30 daysSame as results, 1 hour, 24 hours, 7 days
Uploaded filesReference files1 dayDelete when the job ends

The uploaded-files clock has three important limits:

  • Delete when the job ends: an upload is removed once every task using it reaches a final state, normally within a minute. A new generation using that deleted reference needs another upload.
  • Existing files only: that switch applies to files present when you save. Later uploads currently keep the standard 1-day expiry shown in their commit response.
  • 1-hour and 24-hour choices: these currently change nothing; the upload remains usable until its returned expiresAt.

Warning before you shorten anything: a shorter setting can reach back to tasks you already ran. Setting Prompt text to 1 or 24 hours, for example, clears the prompt text and the generated results of every task finished more than a day ago, even if Generated results is still 14 days. Deleted content cannot be restored. Download what you want to keep first; lengthening a setting only affects the future.

2. One request at a time. Send the X-Spicy-Retention header (seconds) when creating a task; the retention documentation shows the request. The effective window is the shortest of that request, your account setting and the platform cap. Read the accepted deadlines from the task rather than promising the requested duration.

Do not use immediate deletion for a product that promises delivery or a saved library. It can remove the result before your copy finishes. Leave a recovery margin after delivery.

3. Destroy a finished task. Once you have copied what you need, or when a customer requests deletion, remove that task's creative content.

The console offers the same action as Destroy outputs on a task in Logs. Three rules apply:

  • Finished tasks only. Purge is idempotent by taskId; it needs no Idempotency-Key. It neither cancels generation nor refunds the charge, and billingRetained remains true.
  • Deletion is scheduled. contentState becomes purged while mediaDeletionPending stays true until the sweep finishes, normally within a minute. Confirm completion before telling a customer the bytes are gone.
  • A present response removed nothing. Investigate the response and preservation settings rather than reporting deletion completed.

contentState is expired when the retention clock removed the content and purged when you destroyed it. The task state expired is something else entirely: the generation timed out and produced nothing. Retrying helps only in that second case.

Send reference files

A reference image, video or audio file can reach a task three ways. A public HTTPS URL must return the file itself: a link to a share page (cloud drive, photo album, social post) returns a web page and the task fails with invalid_asset, so download the file and upload it instead. A small image (up to 1 MiB) can go inline as a base64 data URI. Anything private or large should be uploaded through the SDK, CLI or Playground, which returns a private spicy:// reference for the task.

Upload limits: JPEG, PNG, WebP and GIF up to 10 MiB; WAV, MP3, WebM, MP4 and MOV up to 90 MiB and 600 seconds, and a model can accept less. Keep an original copy if you will need the input again after its one-day window. Your backend only needs to authorize the upload and record ownership; the client can send the bytes directly. Uploading is free; generation is a separate purchase. The media documentation covers the flow.

Results: collect, then copy or let go

Film strips projected onto a single screen: a generic illustration of several inputs becoming one delivered result

A manuscript and landscape frames converge on a single projected scene.

Submit each new request with its own idempotency key, keep the task ID, and collect the result by polling or callback. Ready assets carry a signed url; fetch it without an API key and send a User-Agent such as Mozilla/5.0, because the CDN rejects Python's default urllib agent with a 403 that does not mean the link expired. A succeeded task can still hold a pending asset, so keep checking until the URL is ready. An expired link can be refreshed within retention; the media documentation shows how.

Three states of an asset are worth handling explicitly:

What you seeMeaningWhat to do
pending: true, no url yetThe file is still being copied into storageQuery again in a few seconds
unavailable: true, no keyNo retrievable platform asset: initial storage failed, retention ended or purge removed itRecover a verified copy you saved; if none exists, explicitly decide on a new generation
HTTP 410 from download-urlThe platform copy is past retention or was destroyedThe platform copy cannot be restored; use your own archive if available

A text-only model has no assets at all, and its text in output.text is erased on the same schedule, so read it before assuming a file exists.

The no-charge storage exception applies when none of a task’s outputs could initially be stored. An old unavailable asset alone does not establish a refund; check the original task’s settlement.

Callbacks carry your prompt and signed result links. Your endpoint, reverse proxy, error tracker and log pipeline then receive material that SpicyAPI itself erases on a schedule, so redact callback bodies from access logs and do the copying in a worker. Signature checking, deduplication and retries are in the webhook documentation.

  • Your product promises a library, sharing, or later editing: stream the result to private storage you control as soon as you see success, record your own asset ID, and (if you want the platform copy gone) call purge afterwards. Stream rather than buffer a large video, and make the destination write idempotent on task plus asset.
  • One-time delivery: do not copy. Show the result, tell the customer how long it lasts, and let the retention clock, or a short X-Spicy-Retention, remove it.

A user-uploaded reference is not a marketing asset, and a successful result is not consent to publish it. Only mark something "saved by customer" after your own copy is confirmed.

When something fails

BoundarySymptomRight recovery
Create taskResponse lostReplay the saved body with the same idempotency key within its 24-hour deduplication window; stop for reconciliation when that window may have elapsed. A new key can create a second task and charge
CallbackDuplicate, late, or missedDeduplicate by request_id; poll recordInfo when an expected terminal event never arrives
Result copyLink expired before a queued fetch or reconnectionFetch a fresh URL and stream again to the same destination key
Past the deadline410, or unavailableCheck your verified archive first; mark unavailable if no saved copy remains

Keep logs useful without keeping creative material

Check these routes for accidental copies:

  • Error reports and access logs: redact prompts, tickets and signed links; avoid logging media-route bodies.
  • Analytics and queues: use opaque operation, task and asset IDs rather than URLs or filenames, including in dead-letter storage.
  • Support exports and public delivery: check screenshots, page metadata and emails. Send customers to an authenticated page that issues a fresh link after checking access.
  • Your storage and backups: apply your own deletion policy. An expired link cannot revoke a file someone already downloaded.

What retention settings cannot promise

  • The model sees the prompt. The model that runs a request receives it in plaintext, so SpicyAPI's settings control only how long SpicyAPI itself keeps something. Do not send material you do not need to send.
  • Purge is an asynchronous deletion request. Confirm its returned content state and completion of media deletion. Storage lifecycle cleanup and backup rollover have separate clocks; your own copied files and backups also need their own deletion operation. Billing records stay either way.

If you need a different retention period written into a contract, raise it before signing rather than inferring it from a documentation page.

FAQ

Can I use a temporary upload URL as an image URL in a generation request?

No. The upload URL only authorizes the direct write. Upload, commit, and put the committed spicy:// URI in a field the live model schema marks as an upload field.

Can I keep a generated video on SpicyAPI longer than 14 days?

For API, SDK and Playground results, no: their cap is about 14 days. Studio short-film media has a separate cap of about 60 days. Copy the file to your own storage after success for longer access.

Does purge refund the task?

No. Purge removes content only; the charge and task record stay.

Can a webhook replace polling completely?

It can be the main path, with a bounded reconciliation check for missed deliveries. Key your handler on the delivery request_id and the task ID.

Avoid it. Emails are forwarded and archived long after a short-lived link expires. Send customers to an authenticated page that checks access and issues a fresh link.

What should happen when a customer deletes a saved result?

Delete or revoke your own copy and its delivery path, and keep a record that you did. The platform's copy follows its own schedule; use Destroy outputs if it should go sooner.

Check an existing task from code

Install spicyapi, set SPICY_API_KEY and TASK_ID, then run this read-only check. It does not create a generation or delete content.

python
import json
import os
from spicyapi import SpicyClient

client = SpicyClient()
task = client.get_task(os.environ["TASK_ID"])
print(json.dumps({"taskId": task["taskId"], "state": task["state"],
    "contentState": task.get("contentState"), "retention": task.get("retention"),
    "mediaDeletionPending": task.get("mediaDeletionPending")}, indent=2))

The retention reference covers the request settings and deletion contract.

Let an Agent handle the call

Delegate a storage check when you already have a task ID; no new generation is needed.

  • CLI: npx @spicyapi/cli tasks get "$TASK_ID" reads the current deadlines. See the CLI guide.
  • MCP: ask spicyapi_task_get to inspect that task. Use spicyapi_task_purge only after explicitly approving destruction of its content; the MCP guide covers confirmation.
  • Skill: after npx skills add spicyapi-ai/spicy-skill, ask $spicyapi to inspect the task's retention and explain what will expire. See the Skill guide.

Also in 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Русский · Italiano · Polski

Try it yourself

Pay only for what you run — no plan, no subscription.

Made with MiniMax H3 · ByteDance Seedance 2.0 Fast