Upload big files with the tus protocol (version 1.0.0). A request that fails costs one part, and an upload that was cut (the connection, the program, the computer) is picked up where it stopped, also hours later. Any tus client works. This page tells how to get the address of the upload from the API and how to have the file finished by the last request.

GET

https://send.now/api/upload/chunk?key=1ltghrilhllgrx2b2

Parameters Description Example Format Required
key API-Key 1ltghrilhllgrx2b2 String yes
srv_id The srv_id of an upload that is not finished: you are given the same file server again, as long as it takes uploads. Leave it out for a new file 12 Number no

Step 1 - ask for an upload address


{
  "msg": "OK",
  "status": 200,
  "tus_url": "https://u7134.send.now/cgi-bin/tus.cgi",
  "srv_id": 12,
  "upload_token": "1791160000.3fa9c1d3e5...",
  "upload_limit": "1791123456.2147483648.9c1b7e0d44...",
  "sess_id": "ynfejiddf0grvip0",
  "api_url": "https://u7134.send.now/cgi-bin/api.cgi?u=api",
  "chunk_url": "https://u7134.send.now/cgi-bin/put_chunk.cgi?u=api",
  "server_time": "2024-08-26 12:19:28"
}
          
FieldDescription
tus_urlWhere to create the upload. Not in the reply when the site does not offer tus: use Chunked upload then
srv_idThe file server of tus_url. Keep it with the upload and send it back in step 1 when you ask again for an upload that is not finished
upload_tokenSend it as the header X-Upload-Token with every request to the file server, when it is not empty. Valid for 12 hours
upload_limitSend it as the header X-Upload-Limit when creating the upload, when it is not empty: it carries the largest file your account may upload, and the file server refuses a bigger file at once (413) instead of after the last byte. Empty when your account has no limit
sess_idIt says whose account gets the file. Valid for about an hour: ask for it again just before the last request of a long upload (step 4)
api_url, chunk_urlFor Chunked upload, and for finishing an upload without X-Import (see below)

Step 2 (optional) - ask whether the file may be uploaded

https://send.now/api/upload/precheck?key=1ltghrilhllgrx2b2&name=big.zip&size=2400000000

The answer is the one the file server's import would give after all the bytes: the file is too big for your account, its storage is used up, the cap per day is reached, the type of file is not allowed. Nothing is stored. fld_id (a folder of yours) and srv_id are optional.


{ "status": 200, "msg": "OK", "allowed": 1, "checked": 1 }

{ "status": 200, "msg": "file is too big", "allowed": 0, "error": "file is too big" }
          

The call is only a help: the site decides again when the file is finished. "checked": 0 means that nobody was asked (the site has the question off) and the file may be sent. A refused file has status 200 with "allowed": 0 and the reason in msg.

Step 3 - create the upload

POST tus_url
HeaderDescriptionExampleRequired
Tus-Resumable1.0.0, on every request1.0.0yes
Upload-LengthThe size of the file in bytes2400000000yes
Upload-Metadatafilename and filetype as tus wants them: a name, a space, the value in base64, pairs separated by commasfilename Ymlnemlwno
X-Upload-Tokenupload_token of step 11791160000.3fa9...when not empty
X-Upload-Limitupload_limit of step 11791123456.2147...when not empty

The reply is 201 with the header Location: the address of this upload, a path on the file server (/cgi-bin/tus.cgi/0123456789abcdef0123456789abcdef). Keep it with srv_id, the size and the file: it is all you need to go on after a stop.

Step 4 - send the file

PATCH the address of the upload
HeaderDescriptionExampleRequired
Tus-Resumable1.0.01.0.0yes
Upload-OffsetHow many bytes the file server has: 0 for the first part, then the Upload-Offset of the last answer52428800yes
Content-Typeapplication/offset+octet-streamyes
X-Upload-Tokenupload_token of step 11791160000.3fa9...when not empty
X-ImportOn the request that sends the last byte: asks for the file to be finished with it. A query string, see belowsess_id=ynfejiddf0grvip0&fname=big.zip&file_public=0&u=apion the last request

The body is the next part of the file, as big as you like (50 MB is a good size). The reply is 204 with the new Upload-Offset. Send the parts one after the other.

The fields of X-Import are written like the parameters of a URL (percent-encoded; at most 4 KB):

FieldDescriptionExampleRequired
sess_idsess_id of step 1ynfejiddf0grvip0yes
fnameName of the file (the filename of the metadata if you leave it out)big.zipno
file_public1 = public, 0 = private. Send it, do not rely on the default0no
file_descrDescriptionBackupno
to_folderId of one of your folders (default: the top level)58no
link_passPassword for the file123passwordno
uapiapino

The reply to the request that carried X-Import comes when the file is saved, and says how it went in headers (the status stays 204, the bytes are all there):


X-Import-Status: OK
X-File-Code: byul9fp3ctyr
X-Delete-Link: https://send.now/byul9fp3ctyr?killcode=77b1an60zs

X-Import-Status: ERROR
X-Import-Error: file is too big
          

The link of the file is https://send.now/ followed by X-File-Code. An ERROR is final: the site refused this file, the upload is gone, send the file again only when the reason is gone.

Step 5 - after a stop: where was I?

HEAD the address of the upload  Tus-Resumable: 1.0.0 and X-Upload-Token

The reply has Upload-Offset, the bytes the file server has. Go on with step 4 from there. Do this after any request that failed or whose answer you did not get, and when the program starts again with an upload that is not finished (ask for step 1 again first, with the srv_id you kept: you get a new token and session for the same file server). A file that is already finished answers Upload-Offset equal to its length with the same X-Import-Status and X-File-Code headers: the answer to the last request is never lost. 404 or 410 means the upload is gone (an upload that nobody touches for 24 hours is removed): start again with step 3.

Without X-Import

A client that does not send X-Import (or a file server that does not know it: the reply of the last request has no X-Import-Status) finishes the upload as in Chunked upload, step 3: POST api_url with op=import_file, sid = the last part of the address of the upload (32 letters and digits), sess_id and fname.

cURL example


# 1. address, token, session
curl 'https://send.now/api/upload/chunk?key=1ltghrilhllgrx2b2'

# 3. create the upload: the size in bytes, the name in base64
curl -i -X POST 'TUS_URL' -H 'Tus-Resumable: 1.0.0' -H 'X-Upload-Token: UPLOAD_TOKEN' -H 'X-Upload-Limit: UPLOAD_LIMIT' \
  -H 'Upload-Length: 10485760' -H "Upload-Metadata: filename $(printf 'big.zip' | base64)"
# 201 Created   Location: /cgi-bin/tus.cgi/0123456789abcdef0123456789abcdef

# 4. send the file (here in one request, which is also the last one)
curl -i -X PATCH 'https://u7134.send.now/cgi-bin/tus.cgi/0123456789abcdef0123456789abcdef' \
  -H 'Tus-Resumable: 1.0.0' -H 'X-Upload-Token: UPLOAD_TOKEN' -H 'Upload-Offset: 0' \
  -H 'Content-Type: application/offset+octet-stream' \
  -H 'X-Import: sess_id=SESS_ID&fname=big.zip&file_public=0&u=api' --data-binary @big.zip
# 204 No Content   X-Import-Status: OK   X-File-Code: byul9fp3ctyr

# 5. where was I? (after a stop)
curl -I 'https://u7134.send.now/cgi-bin/tus.cgi/0123456789abcdef0123456789abcdef' -H 'Tus-Resumable: 1.0.0' -H 'X-Upload-Token: UPLOAD_TOKEN'
          

Notice

Use the addresses of step 1 for all the steps: the bytes are kept on that file server. upload_token works for 12 hours, sess_id for about an hour, and an upload that is not touched for 24 hours is removed.
An upload that takes longer than an hour: ask step 1 again (with srv_id) just before the request that sends the last byte, and use the new sess_id in X-Import.
A file server answers GET tus_url with a few lines of text: tus 1.0.0, and the words upload-limit and import when it takes X-Upload-Limit and X-Import. Use it to find out whether the file server can do what you want before you ask for it.
The size and storage limits of your account are checked when the file is finished. X-Upload-Limit and the precheck (step 2) only tell you earlier.
A part that is sent at a place the file server is not at (it has more or fewer bytes than the Upload-Offset says) is answered with 409 and the offset it has; a very big part may instead get a dropped connection. Both ways, ask HEAD and go on from its offset.

Status code of the file server

201 / 204 Created / the part is saved
400 / 412 / 415 Bad request: a header is missing or wrong (Tus-Resumable, Upload-Length, Upload-Offset, Content-Type)
403 The token is missing, wrong or has run out: ask step 1 again
404 / 410 No such upload, or it has expired: start again with step 3
409 The file server is at another offset (Upload-Offset of the answer): go on from there
413 The file is too big for your account (X-Upload-Limit), or for the file server. The answer says how big a file may be
423 The upload is in use by a request that is still running: wait a moment and ask HEAD