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 eitherPOST
orPUT
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:
$API_KEY
is a MASV API key$TEAM_ID
is 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:
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:
$API_KEY
is a MASV API key$TEAM_ID
is 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_id
is a unique identifier for the webhook eventevent_time
is the timestamp for when the event was generatedevent_type
indicates the subject of the event (ie.package.created
orpackage.finalized
)body_extras
are the key/value pairs supplied on the webhookobject
is the actual record, in this case apackage
type
indicates what the object is, ie.package
id
is the package idname
is the package nameportal_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 isfinalized
.sender
is the email address of the uploading usersize
is the bytes of the total package - note this will be 0 during creation, but will be populated onpackage.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 onpackage.finalized
created_at
is the timestamp for when the package was createdupdated_at
is the timestamp for when the package was last modifiedcustom_webhook_id
is 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_id
is a unique identifier for the webhook eventevent_time
is the timestamp for when the event was generatedevent_type
indicates the subject of the event (ie.package.created
orpackage.finalized
)body_extras
are the key/value pairs supplied on the webhookobject
is the actual record, in this case apackage
type
indicates what the object is, ie.package
id
is the package idname
is the package nameportal_id
is the portal the package was uploaded to (omitted if not a portal package)sender
is the email address of the uploading usersize
is the bytes of the total package - note this will be 0 during creation, but will be populated onpackage.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 onpackage.finalized
created_at
is the timestamp for when the package was createdupdated_at
is the timestamp for when the package was last modifiedcustom_webhook_id
is the identifier of the webhook this event was associated with