Node.js
Created and maintained by WeTransfer
Unfortunately we no longer provide support for the WeTransfer API. Learn more
Welcome to WeTransfer's public API! You can use our API to create transfer links and share files and love all over the world.
First, we have to make sure you’re fully authorized to create a new transfer. You do this by sending two authentication headers with the authorize request.
Next up, we create an empty transfer object and tell it what items to expect in the next step. This is also where we retrieve the URL for the transfer itself.
Then for each file part you request an upload URL that will show you where on Amazon to put it. Repeat until you’ve uploaded all parts and move on to next file.
We make them, you use (and contribute to) them: WeTransfer made SDKs!
Created and maintained by WeTransfer
Created and maintained by WeTransfer
Created and maintained by WeTransfer
You make them, we present them: community made SDKs!
Created and maintained by Arkaitz Garro
Created and maintained by Tim Faber
Created and maintained by André Steffens
Created and maintained by Andreas Strikos
To be able to use our APIs, you must provide a secret api key on every request. You can create a key on our Developer Portal. Please make sure that you keep your API key in a secret place, and it's not shared on CVS repositories or client side code.
Our APIs expect the API key to be included as a header on every API requests. Please provide the API key using x-api-key
header, like in the following example:
We also require a Content-Type: application/json
header on every request, otherwise you will receive an "Unsupported Media Type" error.
Besides the API Key and the Content-Type header, a JSON Web Token (JWT) must be included on subsequent requests. To retrieve a JWT, send a request, including your API token to the following endpoint:
curl -X POST \
https://dev.wetransfer.com/v1/authorize \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key"
require 'we_transfer_client'
# Please keep in mind that authorization is performed when the client is initialized.
client = WeTransferClient.new(api_key: '# YOUR PRIVATE API KEY GOES HERE'))
const createWTClient = require('@wetransfer/js-sdk');
// Please keep in mind that authorization is performed when the client is initialized.
const apiClient = await createWTClient('/* YOUR PRIVATE API KEY GOES HERE */');
// When using the SDK, there is no need to call authorize manually.
// The method is available though, in case you need to access the JWT.
const auth = await apiClient.authorize();
<?php
\WeTransfer\Client::setApiKey(getenv['WT_API_KEY']);
// When using the SDK, there is no need to call authorize manually.
// The method is available though, in case you need to access the JWT.
$token = \WeTransfer\Client::authorize();
name | type | required | description |
---|---|---|---|
x-api-key |
String | Yes | Private API key |
Content-Type |
String | Yes | must be application/json |
{
"success": true,
"token": "A valid JWT token here"
}
name | type | description |
---|---|---|
success |
Boolean | Successful request, or not. |
token |
String | A JWT token valid for one year, if authorization went well |
Transfers can be created with or without items. Once the transfer has been created, items can be added at any time.
curl https://dev.wetransfer.com/v1/transfers \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key" \
-H "Authorization: Bearer jwt_token" \
-d '{"name": "My very first transfer!"}'
transfer = client.create_transfer(name: 'My very first transfer!', description: 'Something about cats, most probably.') do |builder|
builder.add_file(name: File.basename(__FILE__), io: File.open(__FILE__, 'rb'))
builder.add_file(name: 'cat-picture.jpg', io: StringIO.new('cat-picture'))
builder.add_file(name: 'README.txt', io: File.open('/path/to/local/readme.txt', 'rb'))
builder.add_file_at(path: __FILE__)
end
const transfer = await apiClient.transfer.create({
name: 'My very first transfer!',
description: 'Something about cats, most probably.'
});
<?php
$transfer = \WeTransfer\Transfer::create(
'My very first transfer!',
'Something about cats, most probably.'
);
name | type | required | description |
---|---|---|---|
x-api-key |
String | Yes | Private API key |
Authorization |
String | Yes | Bearer JWT authorization token |
Content-Type |
String | Yes | must be application/json |
name | type | required | description |
---|---|---|---|
name |
String | Yes | Something about cats or coffee, most probably |
description |
String | No | A description, if needed |
{
"id": "random-hash",
"version_identifier": null,
"state": "uploading",
"shortened_url": "https://we.tl/s-random-hash",
"name": "Little kittens",
"description": null,
"size": 0,
"total_items": 0,
"items": []
}
Creates a new empty transfer.
👉🏻 Note: the shortened_url
in the response is the URL you will use to access the transfer you create! It is not returned at the end of the upload flow, rather when you create the empty transfer. 👈🏻
Once a transfer has been created you can then add items to it.
curl https://dev.wetransfer.com/v1/transfers/{transfer_id}/items \
-H "x-api-key: your_api_key" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer jwt_token" \
-d '{"items": [{"local_identifier": "delightful-cat", "content_identifier": "file", "filename": "kittie.gif", "filesize": 1024}, {"local_identifier":"favourite-site", content_identifier: "web_content", "url":"https://developers.wetransfer.com", "meta":{"title":"My Favourite Developers Portal!"}}]}'
const fileItems = await apiClient.transfer.addFiles(transfer, [{
filename: 'kittie.gif',
filesize: 1024
}]);
const linkItems = await apiClient.transfer.addLinks(transfer, [{
url: 'https://wetransfer.com',
meta: {
title: 'WeTransfer'
},
}]);
<?php
\WeTransfer\Transfer::addLinks($transfer, [
[
'url' => 'https://en.wikipedia.org/wiki/Japan',
'meta' => [
'title' => 'Japan'
]
]
]);
\WeTransfer\Transfer::addFiles($transfer, [
[
'filename' => 'Japan-01.jpg',
'filesize' => 13370099
]
]);
name | type | required | description |
---|---|---|---|
x-api-key |
String | Yes | Private API key |
Authorization |
String | Yes | Bearer JWT authorization token |
Content-Type |
String | Yes | must be application/json |
name | type | required | description |
---|---|---|---|
items |
Array(Item) | Yes | A list of items to send to an existing transfer |
An item can be either a file or an URL.
File object
name | type | required | description |
---|---|---|---|
filename |
String | Yes | The name of the file you want to show on the items list. Must be less than 255 characters! |
filesize |
Integer | Yes | File size in bytes. Must be accurate. No fooling. Don't let us down. |
content_identifier |
String | Yes | Must be "file". |
local_identifier |
String | Yes | Unique identifier to identify the item locally (to your system). Must be less than 36 characters! |
URL object
name | type | required | description |
---|---|---|---|
url |
String | Yes | A complete URL. Must be less than 2000 characters! |
content_identifier |
String | Yes | Must be "web_content". |
local_identifier |
String | Yes | Unique identifier to identify the item locally (to your system). Must be less than 36 char`acters! |
meta |
Object | Yes | You can use this to store the metadata of the URL. For example: "meta": {"title":"The Best URL EVER!"} The complete meta string Must be less than 3000 characters! |
[{
"id": "random-hash",
"content_identifier": "file",
"local_identifier": "delightful-cat",
"meta": {
"multipart_parts": 3,
"multipart_upload_id": "some.random-id--"
},
"name": "kittie.gif",
"size": 195906,
"upload_id": "more.random-ids--",
"upload_expires_at": 1520410633
},
{
"id": "random-hash",
"content_identifier": "web_content",
"meta": {
"title": "WeTransfer"
},
"url": "https://wetransfer.com"
}]
It will return an object for each item you want to add to the transfer. Each item must be split into chunks, and uploaded to a pre-signed S3 URL, provided by the following endpoint.
Important Chunks must be 6 megabytes in size, except for the very last chunk, which can be smaller. Sending too much or too little data will result in a 400 Bad Request error when you finalize the file.
To be able to upload a file, it must be split into chunks, and uploaded to different presigned URLs. This route can be used to fetch presigned upload URLS for each of a file's parts.
curl "https://dev.wetransfer.com/v1/files/{file_id}/uploads/{part_number}/{multipart_upload_id}" \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key" \
-H "Authorization: Bearer jwt_token"
name | type | required | description |
---|---|---|---|
x-api-key |
String | Yes | Private API key |
Authorization |
String | Yes | Bearer JWT authorization token |
Content-Type |
String | Yes | must be application/json |
name | type | required | description |
---|---|---|---|
file_id |
String | Yes | The public ID of the file to upload, returned when adding items. |
part_number |
Number | Yes | Which part number of the file you want to upload. It will be limited to the maximum multipart_parts response. |
multipart_upload_id |
Number | Yes | The upload ID issued by AWS S3. |
{
"upload_url": "https://presigned-s3-put-url",
"part_number": 1,
"upload_id": "an-s3-issued-multipart-upload-id",
"upload_expires_at": 1519988329
}
The Response Body contains the upload_url
, part_number
, upload_id
, and upload_expires_at
.
If the requester tries to request an upload URL for a file that is not in one of the requester's transfers, we will respond with 401 UNAUTHORIZED.
If a request is made for a part, but no multipart_upload_id
is provided; we will respond with a 400 BAD REQUEST as all consecutive parts must be uploaded with the same multipart_upload_id
.
Please note: errors returned from S3 will be sent as XML, not JSON. If your response parser is expecting a JSON response it may throw an error here. Please see AWS' S3 documentation for more details about specific responses.
curl -T "./path/to/kittie.gif" "https://signed-s3-upload-url"
// Depending on your application, you will read the file using fs.readFile
// or it will be a file uploaded to your service.
const files = [[/* Buffer */], [/* Buffer */]];
await Promise.all(transferItems.map((item, index) => {
return apiClient.transfer.uploadFile(item, files[index]);
}));
<?php
foreach($transfer->getFiles() as $file) {
\WeTransfer\File::upload($file, fopen(realpath('./path/to/your/files.jpg'), 'r'));
}
After the file upload is successful, the file must be marked as complete.
curl -X https://dev.wetransfer.com/v1/files/{file_id}/uploads/complete \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key" \
-H "Authorization: Bearer jwt_token"
name | type | required | description |
---|---|---|---|
x-api-key |
String | Yes | Private API key |
Authorization |
String | Yes | Bearer JWT authorization token |
Content-Type |
String | Yes | must be application/json |
name | type | required | description |
---|---|---|---|
file_id |
String | Yes | The public ID of the file to upload, returned when adding items. |
In working with the WeTransfer API you might come across some errors. Here are some of the most common, and what you can do about them.
Error | Message | Explanation | Solution |
---|---|---|---|
Missing Authentication Token | {"message":"Missing Authentication Token"} |
Despite what you might think, this actually just means that you're hitting an endpoint that doesn't exist. | Check that you've spelled the endpoint correctly, and remember that our API is versioned - dev.wetransfer.com/authorize won't work, but dev.wetransfer.com/v1/authorize will. |
Forbidden | {"message":"Forbidden"} |
You've forgotten to send us your API key, or it's being improperly sent. | Make sure that you're sending your API key with each request - see the example code, or add a header like so: X-API-KEY: <your api key> . |
Unsupported Media Type | {"message":"Unsupported Media Type"} |
You've sent a request to the API without a Content-Type set, or incorrectly set. |
Make sure that you're sending a Content-Type: application/json header with each request. |
Unsupported HTTP Method | {"message":"Unsupported HTTP method"} |
You've sent a request to an endpoint using the wrong HTTP method. For example, you've sent a POST request to an endpoint that expects a GET. | Make sure that you're using the correct HTTP verb for each endpoint. |
API Rate Limit | {"message":"Limit Exceeded Exception"} or a 429 response |
You've exceeded your rate limit. | Try again but with fewer requests in a given time period, wait until tomorrow, or even better: email us (developers@wetransfer.com) and we can talk extending the limit. |
Expected X to be Y | {"message":"Expected 1200 to be 3243214"} |
If the size of the file you send does not match the size of the file you told us to expect, you'll see this message when you send a /complete request. | Check that you're properly computing the size of the file, or that you're uploading all the required chunks (before sending the complete call). |
Because file uploads go directly to S3, any errors during this step of the process will be returned in XML. Please see the official S3 documentation for details of individual AWS S3 responses.
The WeTransfer API uses the following conventional error codes:
Code | Meaning |
---|---|
400 |
Bad Request -- Your request is invalid. |
403 |
Forbidden -- Your API key is wrong. |
404 |
Not Found -- The specified resource could not be found. |
405 |
Method Not Allowed -- You tried to access a transfer with an invalid method. |
406 |
Not Acceptable -- You requested a format that isn't json. |
410 |
Gone -- The transfer requested has been removed from our servers. |
418 |
I'm a teapot. |
429 |
Too Many Requests -- You're requesting too many things! Slow down! |
500 |
Internal Server Error -- We had a problem with our server. Try again later. |
503 |
Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
date | change | api / portal / documentation |
---|---|---|
2018-07-25 | Clarify shortened_url, copy fixes | documentation |
2018-07-24 | Add PHP code snippets | documentation |
2018-07-18 | Clarify a couple of required params and add errors documentation | documentation |
2018-07-10 | Deprecate TLS 1.0 and 1.1 on developers portal | portal |
2018-07-06 | Add changelog to documentation | documentation |
2018-06-22 | Add ability for users to create multiple keys | portal |
2018-05-30 | Add HSTS header to API endpoints | api and portal |
2018-05-14 | Release initial version of API to the world | all |