Skip to content

Large files

POSThttps://api.kennmarq.com/v1/uploads

A request to the API carries at most 4 MB. For a larger file, up to 25 MB (a clip to mark, up to 1 GB), upload it first, straight to our storage in Zurich, then name the upload instead of sending the file. The Python SDK does this by itself.

How it works

  1. Ask for an upload with the file's size: {"bytes": 12345678}.
  2. PUT the file to the url you get back, with its headers, within 15 minutes.
  3. Name the upload in upload instead of file on /v1/mark, /v1/check or /v1/verify, or in input_upload instead of input on /v1/mark.
curl
# 1. The upload, for the file's size
curl https://api.kennmarq.com/v1/uploads \
  -H "Authorization: Bearer $KENNMARQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"bytes\": $(wc -c < render.png)}"
# → {"object":"upload","id":"up_…","url":"https://…","method":"PUT","headers":{"Content-Length":"…"},…}

# 2. The file, to the url (no Authorization header: the URL is the permission)
curl -X PUT --upload-file render.png "$UPLOAD_URL"

# 3. The call, naming the upload
curl https://api.kennmarq.com/v1/mark \
  -H "Authorization: Bearer $KENNMARQ_API_KEY" \
  -F upload=up_… -F source=created \
  -o render.marked.png

Request

application/json with one field, bytes: the file's size, from 1 byte to 1 GB (1,073,741,824 bytes). Each call holds the files it reads to its own limit: 25 MB (26,214,400 bytes), and 1 GB for a clip to mark; a call naming a larger upload answers 413 payload_too_large. Needs a key with the mark or check scope. Asking for an upload counts toward the organisation's calls a minute, never toward its marks; a key may have 100 uploads waiting at once.

Response

201, application/json:

Fields of an upload
FieldValue
object"upload"
idThe upload's ID (up_…): name it in the call's upload field.
bytesThe size you declared; the file must be exactly this long.
urlWhere to PUT the file: our storage in Zurich. The URL itself is the permission, so send no Authorization header.
method"PUT"
headersHeaders the PUT must carry: Content-Length, which the URL is signed for.
url_expires_atThe URL works for 15 minutes.
expires_atThe upload can be used for an hour; then it's deleted unused.

The rules

  • An upload works once, within the hour, with the key that made it. Another key, a second call, or a later one gets 404 upload_not_found.
  • The PUT must send exactly the declared size; anything else is refused. A call naming an upload whose file hasn't arrived yet gets 400 invalid_request.
  • A call that fails for a reason of its own (a typo in an option, our service down for a moment) leaves the upload for the retry. A call that used it, or refused what it holds (not a file it takes, or blocked by the safety check), uses it up. A clip's job keeps its upload until the job is done; after a failure on our side it works again for its hour.
  • On /v1/verify, which needs no key for a file sent in the request, naming an upload takes the key that made it.
An upload's file is deleted as soon as the call has used it, or when it expires unused, an hour after it was made. Like every file you send us, it's read for that one call and kept for nothing else.

Errors

Errors of POST /v1/uploads
StatusCodeWhen
400invalid_requestbytes is missing, not a whole number, or under 1.
400unknown_fieldA field other than bytes.
401missing_api_key, invalid_api_key, api_key_revokedSee authentication.
403insufficient_scope, ip_not_allowedThe key has neither the mark nor the check scope, or the address isn't allowlisted.
413payload_too_largebytes is over 1 GB.
415unsupported_media_typeThe body isn't sent as application/json.
429rate_limitedToo many calls this minute, or 100 uploads already waiting for this key; retry after Retry-After seconds.
503storage_unavailableUploads are down for a moment. Retry.

Error bodies follow the common format.