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 support@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_KEYis a MASV API key$TEAM_IDis the Team ID returned during auth request (refer to Authorization: Login section of this document)$METHODis eitherPOSTorPUT
Attention
The total size of URL + headers + extras + event payload cannot exceed 128 KiB.
Attention
HTTPS endpoints must have a valid TLS 1.2 or 1.3 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_KEYis a MASV API key$CUSTOM_WEBHOOK_IDis 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 1.2 or 1.3 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_KEYis a MASV API key$CUSTOM_WEBHOOK_IDis 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:
$API_KEYis a MASV API key$TEAM_IDis the Team ID
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:
connectionsis 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_KEYis a MASV API key$PORTAL_IDis the Portal ID to update$NAMEis the Portal name. All Portal properties are required on update.$ID1the first custom webhook,$ID2the 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:
$API_KEYis a MASV API key$TEAM_IDis the Team ID
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": {
"token": "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_idis a unique identifier for the webhook eventevent_timeis the timestamp for when the event was generatedevent_typeindicates the subject of the event (ie.package.createdorpackage.finalized)body_extrasare the key/value pairs supplied on the webhookobjectis the actual record, in this case apackagetypeindicates what the object is, ie.packageidis the package idnameis the package nameportal_idis the Portal the package was uploaded to (omitted if not a Portal package)progress_channelsincludes 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 isfinalized.senderis the email address of the uploading usersizeis the bytes of the total package - note this will be 0 during creation, but will be populated onpackage.finalizedstateindicates the status of the package (new,finalized,expired)total_filesindicates how many files were uploaded to the package - note this will be 0 during creation, but will be populated onpackage.finalizedcreated_atis the timestamp for when the package was createdupdated_atis the timestamp for when the package was last modifiedcustom_webhook_idis the identifier of the webhook this event was associated with
Note
MASV integrates with PubNub for publishing and subscribing to progress messages. They provide client SDKs in several programming languages. More details can be found on their developer documentation website.
Warning
PubNub has recently migrated their authentication mechanism to rely on tokens instead of authentication codes. The progress_channels auth.token property should be used for all authentication requests with PubNub and the now deprecated auth.auth_key property should no longer be used at all. More details on how to switch from auth_key to token can be found on their migration guide.
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_idis a unique identifier for the webhook eventevent_timeis the timestamp for when the event was generatedevent_typeindicates the subject of the event (ie.package.createdorpackage.finalized)body_extrasare the key/value pairs supplied on the webhookobjectis the actual record, in this case apackagetypeindicates what the object is, ie.packageidis the package idnameis the package nameportal_idis the Portal the package was uploaded to (omitted if not a Portal package)senderis the email address of the uploading usersizeis the bytes of the total package - note this will be 0 during creation, but will be populated onpackage.finalizedstateindicates the status of the package (new,finalized,expired)total_filesindicates how many files were uploaded to the package - note this will be 0 during creation, but will be populated onpackage.finalizedcreated_atis the timestamp for when the package was createdupdated_atis the timestamp for when the package was last modifiedcustom_webhook_idis the identifier of the webhook this event was associated with