Skip to content

Custom Webhooks

The MASV API allows authorized users to connect their account to external webservices to receive notification of activities within MASV via Custom Webhooks. They can be configured to receive a JSON formatted payload for a selection of events and are attached directly to MASV Portal(s). Events are emitted from MASV to each configured endpoint and are attempted up to 5 times.

Note

This feature is only available for a limited number of customers. To request webhooks API access for your team, please contact team@masv.io.

Webhook API Structure

Create Webhook

Authorized users can create custom webhooks for any Team they belong to (subject to access policy).

Method Route
POST /teams/{{ team_id }}/custom_webhooks
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
active String Yes Indicates if the webhook is active or not
body_extras Object No A static list of keys and values to be appended to the body of all events. All values must be strings.
events Object Yes Indicates which events this webhook will receive (see details on supported events below)
headers Object No A static list of header keys and values to be included on every event that is sent
method Object Yes Verb used when event is sent - POST and PUT are currently supported
name Object No Optional internal reference to the webhook and its purpose
url Object Yes The HTTP or HTTPS endpoint for events to be sent to
REQUEST
curl -d "{\"active\": true, \"body_extras\": {\"$KEY1\": \"$VALUE1\", \"$KEY2\": \"$VALUE1\"}, \"events\": [\"package.created\", \"package.finalized\"], \"headers\": {\"$HKEY1\": \"$HVALUE1\", \"$HKEY2\": \"$HVALUE1\"}, \"method\": \"$METHOD\", \"name\": \"$NAME\", \"url\": \"$URL\"}" \
-H "X-API-KEY: $API_KEY" \
-H "Content-Type: application/json" \
-X POST https://api.massive.app/v1/teams/$TEAM_ID/custom_webhooks

Where:

  • $API_KEY is a MASV API key
  • $TEAM_ID is the team ID returned during auth request (refer to Authorization: Login section of this document)
  • $METHOD is either POST or PUT

Attention

The total size of URL + headers + extras + event payload cannot exceed 128 KiB

Attention

HTTPS endpoints must have a valid TLS certificate

The URL will be queried to ensure it is valid. After a successful request where a custom webhook 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

    {
        "active": true,
        "body_extras": {
            "key": "value",
            "key2": "value2"
        },
        "events": [
            "package.created",
            "package.finalized"
        ],
        "id": "ACHSFSDI32343ASD",
        "headers": {
            "key": "value",
            "key2": "value2"
        },
        "method": "POST",
        "name": "Portal Uploads",
        "url": "https://mywebhooks.endpoint"
    }

Update Webhook

Authorized users can update custom webhooks under any team they belong to (subject to access policy).

Method Route
PUT /custom_webhooks/{{ custom_webhook_id }}
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
active String Yes Indicates if the webhook is active or not
body_extras Object No A static list of keys and values to be appended to the body of all events. All values must be strings.
events Object Yes Indicates which events this webhook will receive (see details on supported events below)
headers Object No A static list of header keys and values to be included on every event that is sent
method Object Yes Verb used when event is sent - POST and PUT are currently supported
name Object No Optional internal reference to the webhook and its purpose
url Object Yes The HTTP or HTTPS endpoint for events to be sent to
REQUEST
curl -d '{"active": true, "body_extras": {"$KEY1": "$VALUE1", "$KEY2": "$VALUE1"}, "events": ["package.created", "package.finalized"], "headers": {"$HKEY1": "$HVALUE1", "$HKEY2": "$HVALUE1"}, "method": "$METHOD", "name": "$NAME", "url": "$URL"}' \
-H "X-API-KEY: $API_KEY" \
-H "Content-Type: application/json" \
-X POST https://api.massive.app/v1/custom_webhooks/$CUSTOM_WEBHOOK_ID

Where:

  • $API_KEY is a MASV API key
  • $CUSTOM_WEBHOOK_ID is the custom webhook ID returned during create request

Attention

The total size of URL + headers + extras + event payload cannot exceed 128 KiB

Attention

HTTPS endpoints must have a valid TLS certificate.

The URL will be queried to ensure it is valid. After a successful request where a custom webhook has been created, this endpoint will return an HTTP response with a status code of 200 OK and a body similar to the one below

    {
        "active": true,
        "body_extras": {
            "key": "value",
            "key2": "value2"
        },
        "events": [
            "package.created",
            "package.finalized"
        ],
        "id": "ACHSFSDI32343ASD",
        "headers": {
            "key": "value",
            "key2": "value2"
        },
        "method": "POST",
        "name": "Portal Uploads",
        "url": "https://mywebhooks.endpoint"
    }

Delete Webhook

Authorized users can delete custom webhooks under any team they belong to (subject to access policy).

Method Route
DELETE /custom_webhooks/{{ custom_webhook_id }}
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
Content-Type String Yes Must be application/json
REQUEST
curl -H "X-API-KEY: $API_KEY" \
-H "Content-Type: application/json" \
-X DELETE https://api.massive.app/v1/custom_webhooks/$CUSTOM_WEBHOOK_ID 

Where:

  • $API_KEY is a MASV API key
  • $CUSTOM_WEBHOOK_ID is the custom webhook id returned during creation

After a successful deletion request, this endpoint will return an HTTP response with a status code of 204 No Content and an empty body. Any transfers that are in progress at the time of deletion will complete normally, however the associated portal recipients may not be notified. Any failed transfers will not be retriable once the connection has been deleted.

List Webhooks

Authorized users can list all cloud connections under any team they belong to (subject to access policy).

Method Route
GET /teams/{{ team_id }}/custom_webhooks/
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
REQUEST
curl -H "X-API-KEY: $API_KEY" \
-X GET https://api.massive.app/v1/teams/$TEAM_ID/custom_webhooks

Where:

After a successful request, this endpoint will return an HTTP response with a status code of 200 OK and a body similar to the one below.

    [
        {
            "active": true,
            "body_extras": {
                "key": "value",
                "key2": "value2"
            },
            "connections": 1,
            "events": [
                "package.created",
                "package.finalized"
            ],
            "id": "ACHSFSDI32343ASD",
            "headers": {
                "key": "value",
                "key2": "value2"
            },
            "method": "POST",
            "name": "Demo Portal Uploads",
            "url": "https://mywebhooks.endpoint"  
        },
        ...
    ]

Where:

  • connections is a read-only property representing the number of Portals that have been attached to this webhook

Attach Custom Webhook to Portal

Authorized users can attach custom webhooks to a portal under any team they belong to (subject to access policy). Custom Webhooks can be attached to a portal on either the Create or Update Portal methods via a new property called custom_webhooks. It is expected that the complete list will be passed on every update - any omissions will be removed UNLESS the custom_webhooks property is excluded entirely.

Method Route
PUT /portals/{{ portal_id }}
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
Content-Type String Yes Must be application/json
BODY
Name Type Required Description
custom_webhooks Array of custom webhooks No List of associated connections
# CUSTOM WEBHOOK
Name Type Required Description
id String Yes ID of custom webhook
REQUEST

Note

When updating portals, it is very important that you provide the full portal object. The following example does not contain all portal fields, and should only be used as a reference for adding custom webhooks to this request.

curl -d "{\"name\": \"$NAME\", \"subdomain\": \"$PORTAL_SUBDOMAIN\", \"custom_webhooks\": [{\"id\":\"$ID1\"}, {\"id\":\"$ID2\"}]}, \"has_access_code\": false, \"active\": true}" \
-H "X-API-KEY: $API_KEY" \
-H "Content-Type: application/json" \
-X PUT https://api.massive.app/v1/portals/$PORTAL_ID

Where:

  • $API_KEY is a MASV API key
  • $PORTAL_ID is the Portal ID to update
  • $NAME is the Portal name. All portal properties are required on update.
  • $ID1 the first custom webhook, $ID2 the second custom webhook, etc.

Attention

All attached custom webhooks must be provided in each PUT request or else they will be removed.

After a successful request where a portal has been updated, this endpoint will return an HTTP response with a status code of 200 OK and a body similar to the one below.

{
    "access_level": "regular",
    "access_list": [],
    "active": true,
    "cloud_connections": [
      {
        "connections": 1,
        "created_at": "2024-06-20T19:50:59.109Z",
        "destination": "sample-s3-bucket",
        "id": "01J0VK7K95A2ACFRW3Z93DJ7B2",
        "name": "Amazon S3",
        "provider": "amazon_s3",
        "region": "us-east-1",
        "state": "ok",
        "sync_metadata": true,
        "target_action": "transfer",
        "updated_at": "2024-10-11T18:33:45.031Z"
      }
    ],
    "created_at": "2024-10-28T17:02:09.334Z",
    "custom_expiry_days": 0,
    "custom_webhooks": [
      {
        "id": "01CTJE8TGGEZDNW91C67JSHQW5"
      },
      {
        "id": "01J0VK7K96A2ACFRW3Z93DJ7B2"
      }
    ],
    "disable_upload_receipt": false,
    "expiry": "0001-01-01T00:00:00.000Z",
    "expiry_enabled": false,
    "file_type_restriction_enabled": true,
    "file_type_restriction_exclude": false,
    "file_types": [
      ".mov",
      ".mp4"
    ],
    "has_access_code": false,
    "has_download_password": true,
    "id": "01CTDNW11G67NKHQW5JE8TP2TJ",
    "max_file_count": 10,
    "max_file_size": 1073741824,
    "max_package_size": 53687091200,
    "message": "Hello world!",
    "name": "My Portal",
    "package_name_format": {
      "label": "",
      "value": ""
    },
    "package_name_format_enabled": false,
    "package_size_restriction_enabled": false,
    "recipients": [
      "[email protected]",
      "[email protected]"
    ],
    "subdomain": "customesub",
    "tag": {
      "id": "01CTDNW91C67JSHQW5JE8TGGEZ",
      "name": "test tag name"
    },
    "terms_of_service": {
      "checkbox_label": "I agree to the terms of service",
      "checkbox_url": "http://test.com/customs/tos.html",
      "description": "Term of Service Description",
      "title": "Term of Service Title"
    },
    "terms_of_service_enabled": true,
    "updated_at": "2024-06-11T10:12:01.241Z"
}

List Attached Webhooks

Authorized users can list the custom webhooks on a portal under any team they belong to (subject to access policy). This is visible by retrieving the list of Portals.

Method Route
GET /teams/{team_id}/portals
HEADERS
Name Type Required Description
X-API-KEY String Yes API key
REQUEST
curl -H "X-API-KEY: $API_KEY" \
-X GET https://api.massive.app/v1/teams/$TEAM_ID/portals

Where:

After a successful request, this endpoint will return an HTTP response with a status code of 200 OK and a body similar to the one below.

[
    {
        "id": "01CNH24NGPTJTMXWWM2J8E2V8V",
        "message": "Hello world!",
        "name": "My portal",
        "subdomain": "myportal",
        "has_access_code": false,
        "recipients": [
            "[email protected]",
            "[email protected]"
        ],
        "cloud_connections": [
            {
                "connections": 1,
                "created_at": "2020-09-15T13:32:27.906Z",
                "id": "01EJ8ZEXC2T8D1Y3ZAR3E6GGFB",
                "name": "Frame.io",
                "provider": "frameio",
                "state": "ok",
                "target_action": "transfer",
                "updated_at": "2020-09-15T10:34:39.442Z"
            },
            {
                "connections": 2,
                "created_at": "2020-09-15T13:46:37.854Z",
                "id": "01EJ908VCYMECVH5SPAV9YN92B",
                "name": "BackBlaze",
                "provider": "backblazeb2",
                "state": "ok",
                "target_action": "transfer",
                "updated_at": "2020-09-15T10:33:31.962Z"
            }
        ],
        "custom_webhooks": [
            {
                "active": true,
                "events": [
                    "package.created",
                    "package.finalized"
                ],
                "id": "ACHSFSDI32343ASD",
                "name": "Demo Portal Uploads"
            },
            {
                "active": true,
                "events": [
                    "package.created",
                    "package.finalized"
                ],
                "id": "KSFIJSF43434D",
                "name": "Sample"
            }
        ]
    },
    {
        "id": "01CNEM9H2AG0MVH33X0EVDY8AQ",
        "message": "Hello world, again!",
        "name": "My other portal",
        "subdomain": "myotherportal",
        "has_access_code": false,
        "recipients": [
            "[email protected]"
        ],
        "cloud_connections": [
            {
                "connections": 5,
                "created_at": "2020-09-15T13:32:27.906Z",
                "id": "01EJ8ZEXC2T8D1Y3ZAR3E6GGFB",
                "name": "Amazon S3",
                "provider": "amazon_s3",
                "state": "ok",
                "target_action": "transfer",
                "updated_at": "2020-09-15T10:34:39.442Z"
            },
            {
                "connections": 2,
                "created_at": "2020-09-15T13:46:37.854Z",
                "id": "01EJ908VCYMECVH5SPAV9YN92B",
                "name": "BackBlaze",
                "provider": "backblazeb2",
                "state": "ok",
                "target_action": "transfer",
                "updated_at": "2020-09-15T10:33:31.962Z"
            }
        ],
        "custom_webhooks": []
    },
    ...
]

Event Payload

Webhook events are sent for successful actions in MASV - for example a Package has been successfully created or finalized. The payload will follow a standard format, with small variations based on the source object.

Events are emitted from MASV to each connected webhook and are attempted up to 5 times with an incremental back-off between attempts.

package.created

{
    "event_id": "SFUHDF35DSD88F",
    "event_time": "2021-01-14T10:39:45.334Z",
    "event_type": "package.created",
    "body_extras": {
        "key": "value",
        "key2": "value2"
    },
    "object": {
        "type": "package",
        "id": "JF4D076SA6FA1",
        "name": "Sample Upload",
        "portal_id": "01CYCWJC40RXPK3HNQVYKAX1K1",
        "progress_channels": [
            {
                "auth": {
                    "auth_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                    "channel_name": "proc.upload.JF4D076SA6FA1",
                    "publish_key": "pub-c-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx",
                    "subscribe_key": "sub-c-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"
                },
                "provider": "pubnub",
                "topic": "upload"
            }
        ],
        "sender": "[email protected]",
        "size": 0,
        "state": "new",
        "total_files": 0,
        "created_at": "2021-01-14T10:39:45.334Z",
        "updated_at": "2021-01-14T10:39:45.334Z"
    },
    "custom_webhook_id": "ACHSFSDI32343ASD"
}

Where:

  • event_id is a unique identifier for the webhook event
  • event_time is the timestamp for when the event was generated
  • event_type indicates the subject of the event (ie. package.created or package.finalized)
  • body_extras are the key/value pairs supplied on the webhook
  • object is the actual record, in this case a package
  • type indicates what the object is, ie. package
  • id is the package id
  • name is the package name
  • portal_id is the portal the package was uploaded to (omitted if not a portal package)
  • progress_channels includes credentials for subscribing to upload progress events. This is only present on the creation event as no further updates will be published once the package is finalized.
  • sender is the email address of the uploading user
  • size is the bytes of the total package - note this will be 0 during creation, but will be populated on package.finalized
  • state indicates the status of the package (new, finalized, expired)
  • total_files indicates how many files were uploaded to the package - note this will be 0 during creation, but will be populated on package.finalized
  • created_at is the timestamp for when the package was created
  • updated_at is the timestamp for when the package was last modified
  • custom_webhook_id is the identifier of the webhook this event was associated with

package.finalized

{
    "event_id": "SFUHDF35DSD88F",
    "event_time": "2021-01-14T16:39:56.350Z",
    "event_type": "package.finalized",
    "body_extras": {
        "key": "value",
        "key2": "value2"
    },
    "object": {
        "type": "package",
        "id": "JF4D076SA6FA1",
        "name": "Sample Upload",
        "portal_id": "01CYCWJC40RXPK3HNQVYKAX1K1",
        "sender": "[email protected]",
        "size": 33454545,
        "state": "finalized",
        "total_files": 30,
        "created_at": "2021-01-14T10:39:45.334Z",
        "updated_at": "2021-01-14T16:39:56.350Z"
    },
    "custom_webhook_id": "ACHSFSDI32343ASD"
}

Where:

  • event_id is a unique identifier for the webhook event
  • event_time is the timestamp for when the event was generated
  • event_type indicates the subject of the event (ie. package.created or package.finalized)
  • body_extras are the key/value pairs supplied on the webhook
  • object is the actual record, in this case a package
  • type indicates what the object is, ie. package
  • id is the package id
  • name is the package name
  • portal_id is the portal the package was uploaded to (omitted if not a portal package)
  • sender is the email address of the uploading user
  • size is the bytes of the total package - note this will be 0 during creation, but will be populated on package.finalized
  • state indicates the status of the package (new, finalized, expired)
  • total_files indicates how many files were uploaded to the package - note this will be 0 during creation, but will be populated on package.finalized
  • created_at is the timestamp for when the package was created
  • updated_at is the timestamp for when the package was last modified
  • custom_webhook_id is the identifier of the webhook this event was associated with