Sociaro

Files API — upload, list, get and delete

/v2/files is where your files live on our side: the pictures, clips and sounds you upload, and the results of your jobs. Four routes, the same key as /v2/jobs, no charge for any of them. Every file has a stable link on our CDN that you can put straight into a model's input.

  • Base URL: https://api.sociaro.com
  • Auth: Authorization: Bearer <your-api-key>.
  • Whose files: they belong to the owner of your key, the same owner as your jobs. Keys of one team share their files; keys that are not in a team share them across the whole organisation. A file id that belongs to someone else gets the same 404 as an id that does not exist.

Upload

POST /v2/files. The body is the file itself, as raw bytes, and Content-Type says what kind of file it is. The name is optional, in an X-Filename header.

curl https://api.sociaro.com/v2/files \
  -H "Authorization: Bearer $SOCIARO_API_KEY" \
  -H "Content-Type: image/png" \
  -H "X-Filename: cat.png" \
  --data-binary @cat.png
{"id": "med_3f9c2b7e41a85d06b1c4e9f07a2d8c35",
 "source": "upload",
 "job_id": null,
 "type": "image",
 "content_type": "image/png",
 "bytes": 482113,
 "url": "https://cdn.sociaro.com/v2/files/3f9c2b7e41a85d06b1c4e9f07a2d8c35/9a1e5c0d7b3f4682a1d9e8c7b6f50342.png",
 "filename": "cat.png",
 "created_at": "2026-11-01T12:00:00.457268+00:00"}

The answer is 201. Every upload makes a new file, even when the bytes are the same as before, so if a response is lost, list your files to see whether it was stored.

X-Filename is a label for you and nothing more. Send it percent-encoded UTF-8; control characters are removed and what is left is cut to 255 characters. It is never part of the link.

What can be uploaded

The first bytes of the file have to match the type you declare. A file that does not match is refused, whatever the name says.

picture   image/jpeg   image/png   image/webp   image/gif
clip      video/mp4    video/webm  video/quicktime
sound     audio/mpeg   audio/wav   audio/x-wav   audio/mp4   audio/x-m4a   audio/ogg   audio/flac

Anything else is refused, SVG and HTML included. The limit is 100 MB, counted as 100,000,000 bytes, measured on the bytes we actually receive.

url is a public link that works with a plain GET: no key, no signature, no deadline. Put it wherever a model takes a link to a picture, clip or sound. For example, as the first frame of a Seedance clip on POST /v2/jobs (the envelope, the required Idempotency-Key header and the per-model input are in the Jobs API):

{"model": "bytedance/seedance-2.0",
 "input": {"content": [{"type": "text", "text": "The cat stretches and walks out of the frame."},
                       {"type": "image_url",
                        "image_url": {"url": "https://cdn.sociaro.com/v2/files/3f9c2b7e41a85d06b1c4e9f07a2d8c35/9a1e5c0d7b3f4682a1d9e8c7b6f50342.png"},
                        "role": "first_frame"}],
           "resolution": "480p", "duration": 4, "generate_audio": false}}

The path of the link cannot be guessed, but anyone who has the link can fetch the file: hand it out as you would the file itself.

List

GET /v2/files lists every file you own, newest first: your uploads and the outputs of your jobs.

query parameter
limit 1 to 100, default 50.
after The next_cursor of the previous page. Treat it as opaque.
source upload or job, to see only one of the two.
job_id Only the files of that job. This is how you find the id of a job's output, to delete it.
curl "https://api.sociaro.com/v2/files?limit=2&source=upload" \
  -H "Authorization: Bearer $SOCIARO_API_KEY"
{"data": [{"id": "med_3f9c2b7e41a85d06b1c4e9f07a2d8c35", "source": "upload", "job_id": null, "type": "image",
           "content_type": "image/png", "bytes": 482113,
           "url": "https://cdn.sociaro.com/v2/files/3f9c2b7e41a85d06b1c4e9f07a2d8c35/9a1e5c0d7b3f4682a1d9e8c7b6f50342.png",
           "filename": "cat.png", "created_at": "2026-11-01T12:00:00.457268+00:00"}],
 "has_more": false,
 "next_cursor": null}

While has_more is true, send the next_cursor back as after for the next page.

The fields of a file:

field
id The id to get or delete the file with.
source upload for a file you uploaded, job for an output of one of your jobs.
job_id The job a job file belongs to, otherwise null.
type image, video or audio.
content_type The file's type.
bytes Its size.
url Its link on our CDN. For a job output it is the same link as in that job's outputs[].
filename The X-Filename you sent, or null. Always null for a job output.
created_at When it was stored.
width, height, duration_sec Only on a file where we recorded them, as in outputs[].

Get

GET /v2/files/{id} answers 200 with the same object, or 404.

Delete

DELETE /v2/files/{id} removes the file, an upload or a job output alike:

curl -X DELETE https://api.sociaro.com/v2/files/med_3f9c2b7e41a85d06b1c4e9f07a2d8c35 \
  -H "Authorization: Bearer $SOCIARO_API_KEY"
{"id": "med_3f9c2b7e41a85d06b1c4e9f07a2d8c35", "deleted": true}
  • The gateway never deletes a file on its own. A file stays until you delete it.
  • Deleting the same id again is a 404.
  • After a delete, the link may still be served from the CDN cache for a while. The stored file is gone at once.
  • Deleting a job output removes it from that job's outputs[]. The job stays succeeded and what it cost does not change.
  • A 503 can leave the file partly deleted: its link may already be gone while it is still listed. Send the same DELETE again until it returns 200 or 404.

Errors

The envelope is the one every /v2 route uses: {"error": {"code": …, "message": …}}. Match on code.

status error.code meaning
400 invalid_input The body is empty, the Content-Length is not a number, or a query parameter is not valid.
401 invalid_key The key is missing, wrong or revoked, or it has no account behind it.
404 file_not_found No such file. An id that is not yours looks the same.
408 upload_timeout The body did not arrive within the time allowed. Nothing was stored.
413 file_too_large More than 100,000,000 bytes.
415 unsupported_media_type The Content-Type is missing or not one of the types above.
415 content_type_mismatch The bytes are not what the Content-Type says.
429 too_many_uploads Too many uploads are running at once. Wait the Retry-After seconds and send it again.
503 unavailable Storage or the database is not available. On an upload: nothing was stored. On a delete: send the same DELETE again.

Limits

  • Up to 4 uploads at once for the owner of your key (a team, or the organisation for keys without a team), and 12 at once across the gateway. Beyond that the answer is 429, with Retry-After: 5, before the body is read.
  • An upload has 10 minutes to send its body.
  • Uploading, listing, getting and deleting are free. They are not checked against your balance.