Skip to content

Upload

MASV clients upload files directly to MASV's third-party storage service providers. MASV achieves this by providing pre-signed URL's for the chosen service while abstracting the interaction for each step of the file process.

Uploads examples are demonstrated using curl commands. If you have access to a terminal to run these commands, MASV recommends the use of our TransferAgent that will ease the process of integration.

Info

Once the upload package has been finalized, the transfer is locked and cannot be further modified.

Warning

Upload transfers created through the APIs expire (removed from the service and deleted) after the timeline set in your pricing subscription.

Packages and Authorization Mechanism

Files uploaded to MASV belong to a package object. This package can be thought of as a virtual directory inside of MASV. Each package contains a token that can be used to upload files to that specific virtual directory. A package can be created by interacting with a different API endpoint (for example, portals or teams).

All requests going to upload endpoints require a token passed as an HTTP header defined as X-Package-Token. This token allows the user to add/remove files from the package until the package is finalized.

Lifecycle Of An Upload

When uploading single or multiple files as part of a package, the following steps generalizes the upload interaction:

  • For each file in the package.
  • Add file to the package API Action
  • Create the file in cloud storage
  • Collect metadata from cloud storage service for the file
  • Identify the number of file chunks to split the file
  • Obtain authorized URL's to upload each chunk
  • Upload all chunks to cloud storage
  • Collect metadata from the cloud storage service for each uploaded chunk.
  • Once all chunks are uploaded, send request to finalize file.
  • Finalize package

Info

Once the upload package has been finalized, the transfer is locked and cannot be further modified.

Finalization of the package will then dispatch the file to the intended recipient immediately.

Warning

Please avoid uploading the following files/directories because they tend to change while upload is running which could cause the upload to fail:

  • desktop.ini
  • .DS_Store
  • .fcpcache

MASV Blueprints

MASV's API abstracts interactions with cloud storage services by creating a Blueprint object. This blueprint instructs the clients on which request they need to execute next during the file upload process.

Each blueprint has four properties:

Name Type Required Description
url String Yes URL that the request should be forwarded towards.
method String Yes The HTTP Method to use.
Example: Get, POST, PUT, DELETE
headers JSON Yes Key-value map of header names and their values.
body String Yes HTTP Request body.

Upload API Interaction

Each package belongs to either a team or portal on MASV. Depending on your use case you can create the initial package under either. Other API requests are portal/team agnostic.

1) Create a team/portal package

A. Team Package

Method Route
POST /teams/{team_id}/packages
HEADERS
Name Type Required Description
X-User-Token String Yes User JSON Web Token
Content-Type String Yes Must be application/json
URL Parameters
Name Type Required Description
team_id String Yes The team ID to bind the package to.
BODY
Name Type Required Description
access_limit Integer No Override default number of downloads for the package
description String Yes Description of the package
name String Yes Name of the package
password String No Password to protect download access to the package
recipients String[] Yes Email address of recipient(s)
unlimited_storage Boolean No Enables and disables unlimited storage days for package

B. Portal Package

Method Route
POST /portals/{portal_id}/packages
HEADERS
Name Type Required Description
Content-Type String Yes Must be application/json
X-Access-Code String No URI encoded upload password (if required by the Portal settings)
URL Parameters
Name Type Required Description
portal_id String Yes The portal id to bind the package to. (Retrieved in (Portals))
BODY
Name Type Required Description
description String Yes Description of the package
name String Yes Name of the package
sender String Yes Email address of the portal package sender

Warning

If you set unlimited_storage to true, Unlimited Storage will be activated and Unlimited Storage charges will be incurred daily beyond the free period included with the team subscription for users who have activated their account. Trial accounts cannot extend the expiry beyond the original date given on creation - it can only be set earlier. How does Extended Storage Work?

REQUEST
  curl -d "{\"access_limit\":$ACCESS_LIMIT, \"description\":\"$DESCRIPTION\", \"name\":\"$NAME\", \"password\": \"$PASSWORD\", \"recipients\":[\"$RECIPIENT_EMAIL\"]}" \
  -H "X-User-Token: $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -s -X POST https://api.massive.app/v1/teams/$TEAM_ID/packages

After a successful request where a package has been created, this endpoint will return an HTTP response with a status code of 201 Created and a body similar to the one below.

{
  "access_token": "xxxxxxxxxxxxxxxxx",
  "created_at": "2021-07-26T18:41:24.508Z",
  "custom_expiry": true,
  "unlimited_storage": false,
  "description": "Testing 123",
  "expiry": "2021-08-05T18:41:24.508Z",
  "extra_storage_updated_at": "2021-07-26T18:41:24.508Z",
  "extras": {
      "storage_id": "aws-wdc"
  },
  "id": "01FBJ1Y9GW3DQ1VHBAJZ7J49FQ",
  "name": "File",
  "progress_channels": [
      {
          "auth": {
              "auth_key": "xxxxxxxxxxxxxxxxx",
              "channel_name": "proc.upload.01D72PEE5AH74NR9EG4CZS29JZ",
              "publish_key": "pub-c-xxxxx-xxxxxxxxxxxxx",
              "subscribe_key": "sub-c-xxxxx-xxxxxxxxxxxxx"
          },
          "topic":"upload",
          "provider": "pubnub"
      }
  ],
  "recipients": [
      "[email protected]"
  ],
  "state": "new",
  "updated_at": "2021-07-26T18:41:24.508Z",
  "usage_updated_at": "2021-07-26T18:41:24.508Z"
}

Response Properties:

Property Description
access_token The auth token returned during auth request.
created_at Time that the object was created at
custom_expiry Was a custom expiration set
description The description for the package.
expiry The expiry for the package
extra_storage_updated_at The time the extra storage was updated at.
extras Various extra fields that can be populated by the user
extras.storage_id The storage id for extras.
id The unique package identifier.
name The name of the package
progress_channels PubNub progress events
recipients Array of emails to send the package to.
state Current state of the package
updated_at Last time the package was updated.
usage_updated_at When usage was last calculated.

Note

Take note of the id and the access_token as they are required to interact with the upload API.

2) Add a file to the package

Method Route
POST /packages/{package_id}/files
HEADERS
Name Type Required Description
X-Package-Token String Yes Package JSON Web Token
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
kind String Yes Type of file
Accepted Values: file/directory
name String Yes Filename (in the file system)
path String Yes File's relative path (in the file system)
last_modified String Yes File's last modified date in the file system (in UTC format)
REQUEST PARAMETERS
Name Type Required Description
package_id String Yes Package ID obtained in step 1

Info

For the following request we will use a specific file example:

  • Kind: file
  • Name: my_video.mpeg
  • Path: Same as where the curl command is being executed
  • Size: 210 MiB in size
REQUEST
curl  -d '{"kind":"file", "name":"my_video.mpeg", "path": "", "last_modified":"2018-12-17T16:14:34.450Z"}' \
-H "X-Package-Token: $PACKAGE_TOKEN" \
-H "Content-Type: application/json" \
-s -X POST https://api.massive.app/v1/packages/$PACKAGE_ID/files

After a successful request where a file has been added to the package, this endpoint will return an HTTP response with a status code of 201 Created and a body similar to the one below.

{
  "storage_type": "s3",
  "max_chunk_size": 5368709120,
  "max_chunks_count": 10000,
  "create_blueprint": {
    "headers": {
      "Content-Disposition": "attachment; filename=\"my_video.mpeg\"; filename*=UTF-8my_video.mpeg"
    },
    "method": "POST",
    "url": "https://masv3-storage-prod-wdc.s3-accelerate.amazonaws.com/01D3MNHA6P4XFXDMHJDTXT61CB/01D3MP8G3RBA7A1P0K98VEV2V3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJT7DTCC6DRVEACYQ%2F20190214%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190214T002448Z&X-Amz-Expires=172799&X-Amz-SignedHeaders=host&uploads=&X-Amz-Signature=4bc45729a1e768a04b655f4a5972b548db1f8b359be16e719434bc5cc7ffd019"
  },
  "file": {
    "id": "01D3MP8G3RBA7A1P0K98VEV2V3",
    "last_modified": "2018-12-17T16:14:34.450Z",
    "name": "my_video.mpeg"
  }
}

Response Properties:

Name Type Required Description
storage_type String Yes Type of cloud storage service the file should be uploaded to.
Required value: s3
max_chunk_size String Yes Maximum allowed chunk size by the cloud service.
max_chunks_count String yes Maximum number of chunks allowed for the file.
create_blueprint Blueprint{} yes The request blueprint for creating the file.
file file{} yes File metadata, take note of property: file.id as it is needed later.

3) Create the file in MASV's cloud storage

From Step 2, use the create_blueprint and construct a corresponding HTTP request based on the supplied information. For example, using the create_blueprint above, one can construct a curl request as follows:

curl -H "BLUE_PRINT_HDR" \
-s -X BLUE_PRINT_METHOD 'BLUE_PRINT_URL'

Where:

HEADERS
Name Type Required Description
BLUE_PRINT_HDR String Yes property: headers from CreateBlueprint step.
REQUEST PARAMETERS
Name Type Required Description
BLUE_PRINT_METHOD String Yes property: method from CreateBlueprint step.
BLUE_PRINT_URL String Yes property: url from CreateBlueprint step.

The cloud storage service (in this case Amazon AWS S3) response will be similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<InitiateMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <Bucket>masv3-storage-prod-wdc</Bucket>
    <Key>01D3MNHA6P4XFXDMHJDTXT61CB/01D3MP8G3RBA7A1P0K98VEV2V3</Key>
    <UploadId>Gng8Oh.yKzM41CmGxMRzHkO20GbP2RarZfTJVHHyPGqTVwrHHRgIZKqxMykJBjzDLZ9o3.pyYPwbVbtSI2LDOEa96Mllx6roowA47KHu2GkXcH6PC7qJTFDtYS38SwqI</UploadId>
</InitiateMultipartUploadResult>

Note

Data format in the response will be XML.

Note

Ensure to store property: uploadId from Step 3 as it is metadata required for interacting with the upload API methods related to this file.

4) Obtain upload URLs

This endpoint is used to get pre-signed upload URLs for each of a file's parts. These upload URLs are essentially limited access to storage.

Note

Upload URLs are valid for a limited amount of time and must be re-requested if they expire.

The client can request upload URLs in bulk which will save a lot of back-and-forth communication with the MASV API.

POST /packages/{package_id}/files/{file_id}

HEADERS
Name Type Required Description
X-Package-Token String Yes Package JSON Web Token
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
upload_id String Yes ID for the initiated multi-part upload
PARAMETERS
Name Type Required Description
package_id String Yes Package ID obtained in step 1
file_id string yes File ID obtained from step 1.
start Integer Yes Starting index of the chunk. (zero-indexed)
count Integer Yes Number of chunk requests to generate
REQUEST
curl -d "{\"upload_id\":\"$UPLOAD_ID\"}" \
-H "X-Package-Token: $PACKAGE_TOKEN" \
-H "Content-Type: application/json" \
-s -X POST https://api.massive.app/v1/packages/$PACKAGE_ID/files/$FILE_ID?start=$START&count=$COUNT

Our example requires 3 blueprints (for the 3 chunks it's trying to upload START=0 and COUNT=3).

The start and count parameters provide control over how many bulk chunk requests are obtained. This is useful for times when total file size upfront is unavailable (ie: data streams.)

The server will return an array of blueprints equal to parameter: count. The blueprints are in ascending order based on the chunk index (starting at 0.)

To continue with our example of uploading my_video.mpeg. We would receive the following output:

[
  {
    "method": "PUT",
    "url": "https://masv3-storage-prod-wdc.s3-accelerate.amazonaws.com/01D3MNHA6P4XFXDMHJDTXT61CB/01D3MP8G3RBA7A1P0K98VEV2V3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJT7DTCC6DRVEACYQ%2F20190214%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190214T011216Z&X-Amz-Expires=86399&X-Amz-SignedHeaders=host&partNumber=1&uploadId=Gng8Oh.yKzM41CmGxMRzHkO20GbP2RarZfTJVHHyPGqTVwrHHRgIZKqxMykJBjzDLZ9o3.pyYPwbVbtSI2LDOEa96Mllx6roowA47KHu2GkXcH6PC7qJTFDtYS38SwqI&X-Amz-Signature=a1ac9186728c3b45d21afc48a70d1535f7597b4f885b0c6ce8cafbbdcde72c72"
  },
  {
    "method": "PUT",
    "url": "https://masv3-storage-prod-wdc.s3-accelerate.amazonaws.com/01D3MNHA6P4XFXDMHJDTXT61CB/01D3MP8G3RBA7A1P0K98VEV2V3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJT7DTCC6DRVEACYQ%2F20190214%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190214T011216Z&X-Amz-Expires=86399&X-Amz-SignedHeaders=host&partNumber=2&uploadId=Gng8Oh.yKzM41CmGxMRzHkO20GbP2RarZfTJVHHyPGqTVwrHHRgIZKqxMykJBjzDLZ9o3.pyYPwbVbtSI2LDOEa96Mllx6roowA47KHu2GkXcH6PC7qJTFDtYS38SwqI&X-Amz-Signature=fba71b0a4eaf033ac47c12aaaf310cba5f78280b75e44cb2176d9f3b0e64b794"
  },
  {
    "method": "PUT",
    "url": "https://masv3-storage-prod-wdc.s3-accelerate.amazonaws.com/01D3MNHA6P4XFXDMHJDTXT61CB/01D3MP8G3RBA7A1P0K98VEV2V3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJT7DTCC6DRVEACYQ%2F20190214%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190214T011216Z&X-Amz-Expires=86399&X-Amz-SignedHeaders=host&partNumber=3&uploadId=Gng8Oh.yKzM41CmGxMRzHkO20GbP2RarZfTJVHHyPGqTVwrHHRgIZKqxMykJBjzDLZ9o3.pyYPwbVbtSI2LDOEa96Mllx6roowA47KHu2GkXcH6PC7qJTFDtYS38SwqI&X-Amz-Signature=0e6c68340af207d43efe23812e831ccc93a0f83a2bbf9ca0181051b9798cd6d8"
  }
]

5) Upload the file chunks

We now begin with the actual upload of your file. Using the blueprint received you can upload each chunk as binary data in the request body.

Continuing with our my_video.mpeg upload. We want to upload chunks of 100mb, dd reads in chunk data as bytes. Using a simple converter we can convert 100mb to 104857600 bytes. We input this into our curl command to tell it how many bytes need to be read.

Info

Note: The <() is a bit of bash magic to read a byte range of a file without having to physically chunk it

curl -i -s -X BLUE_PRINT_METHOD "BLUE_PRINT_URL" –-data-binary @FILE_CHUNK,
curl -i -s -X PUT BLUEPRINT_URL \
--data-binary @<(dd if=my_video.mpeg skip=0 count=104857600 iflag=skip_bytes,count_bytes)

Where:

Name Type Required Description
BLUE_PRINT_METHOD String Yes parameter: method obtained in step 5
BLUE_PRINT_URL String Yes parameter: url obtained in step 5
FILE_CHUNK String yes The file chunk to be uploaded

We would receive the following response:

Content-Length: 0
Connection: keep-alive
x-amz-id-2: NgcsGsD8A5YSO+uNfp5plgERV1Y1uPuAAz2mHSQB++1g/MdNBYh6kXrK7zkVHzOxhzSmv4jAu1w=
x-amz-request-id: 65CAB8D270C820CB
Date: Thu, 14 Feb 2019 01:47:39 GMT
ETag: "7be1b3cc95a04a6dd07d157ad6fae64a"
Server: AmazonS3
X-Cache: Miss from cloudfront
Via: 1.1 56f9e0effaf2e1930aee6248ba70abb7.cloudfront.net (CloudFront)
X-Amz-Cf-Id: giSjIOdkcJ4qbIAcPBq--uItpHaRXb-8ER4YUjvQcx-yKTUOjNRQ4w==

Note

For each uploaded chunk, the following metadata must be collected:

  • partNumber which is part of the chunk upload request URL parameters
  • ETag which is returned as a response header by the storage service

6) Publish upload progress

Note

This feature is only available to customers with this feature enabled. To request access to upload progress API and channels for your team, please contact team@masv.io.

MASV integrates with PubNub to indicate overall file upload progress on each package. These progress updates are posted to the progress channel returned in the Create Package response.

Using the credentials returned for the upload topic in the progress_channels property of the response, messages should be publishing following this format:

  {
      "completed": 123544,
      "total": 1073741824,
      "speed_bps": 123,
      "eta": 301.054
  }

Properties:

Name Type Required Description
completed String Yes Current number of bytes successfully uploaded.
total String Yes Total size of all files in package that will be uploaded format: bytes
speed_bps String Yes Rolling average of bits per second
eta String Yes Estimated time of arrival based on speed_bps in seconds.

Note

For more information on integrating PubNub into your client/service refer to their extensive developer documentation..

7) Finalize the file

Once all chunks have been uploaded, the client must inform the API that the file is successfully uploaded to the cloud storage service. This call informs the MASV backend that all uploading for the file is completed and must supply all collected metadata needed to seal the file in storage.

Method Route
POST /packages/{package_id}/files/{file_id}/finalize
HEADERS
Name Type Required Description
X-Package-Token String Yes Package JSON Web Token
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
chunk_extras Array Of Objects Yes Information about all the chunks that make up the file
chunk_extras[$index].partNumber String Yes Chunk part number
chunk_extras[$index].etag String Yes Chunk part hash
chunk_extras[$index].file_extras Array of Objects Yes Chunk part extras
file_extras.uploadId String Yes The ID of the upload provided in from step 3
size Integer Yes The file size
chunk_size Integer * The chunk size used when uploading the file. There is a performance impact if this field is not provided. Providing this field ensures the generation of a manifest file used to verify file integrity. In custom upload implementations, this field should always be provided.
REQUEST
curl -d '{"chunk_extras":[{"partNumber": CHUNK_PART_NUMBER, "etag": CHUNK_ETAG}], "file_extras":{"upload_id": UPLOAD_ID}, "size": FILE_SIZE, "chunk_size": CHUNK_SIZE}' \
-H "X-Package-Token: PACKAGE_TOKEN" \
-H "Content-Type: application/json" \
-s -X POST https://api.massive.app/v1/packages/PACKAGE_ID/files/FILE_ID/finalize 

For our my_video.mpeg example, our JSON body would be similar to below:

{
  "size": 147778580,
  "file_extras": {
    "upload_id": "Gng8Oh.yKzM41CmGxMRzHkO20GbP2RarZfTJVHHyPGqTVwrHHRgIZKqxMykJBjzDLZ9o3.pyYPwbVbtSI2LDOEa96Mllx6roowA47KHu2GkXcH6PC7qJTFDtYS38SwqI"
  },
  "chunk_extras": [
    {
      "partNumber": "1",
      "etag": "\"7be1b3cc95a04a6dd07d157ad6fae64a\""
    },
    {
      "partNumber": "2",
      "etag": "\"ca8e85fc588f90d07449d0303e9cf329\""
    },
    {
      "partNumber": "3",
      "etag": "\"a6a6aa6836a7a70c28a06dec02dbf199\""
    }
  ]
}

On success, the server will respond with an empty body and a 204 No Content status code.

Note

The client has to repeat steps 2-7 for each additional file in the package.

Attention

If the file size submitted in this request does not match the actual size of the object in storage the service will respond with a 409 Conflict status code.

8) Finalize the package

Once all files have been uploaded and finalized, the client must indicate that the package has been completed and ready to be dispatched to the intended recipient.

Attention

Make sure all uplaoded files have been completed and finalized before finalizing the package. Any in-flight, non-finalized files will be dropped when finalize package is called. If no files were uploaded/finalized, this API call will fail.

This call informs that MASV backend that package is ready to be dispatched to the intended recipient. The package will be dispatched to the intended recipient immediately upon the finalize call.

POST /packages/{package_id}/finalize

Note

Once a package is finalized, its expiry and link(s) expiry time are extended by the amount of time the upload took.

HEADERS
Name Type Required Description
X-Package-Token String Yes Package JSON Web Token
Content-Type String Yes Must be application/json
URL Parameters
Name Type Required Description
package_id String yes Package ID obtained in step 1
REQUEST
curl -H "X-Package-Token: $PACKAGE_TOKEN" \
-H "Content-Type: application/json" \
-s -X POST https://api.massive.app/v1/packages/PACKAGE_ID/finalize

On success, the server will respond with an empty body and a 204 No Content status code.

MASV's API allows you to create additional direct-download links or send a link to a specific email recipient after the upload has been finalized. See the Links page for more details and examples.