Skip to content

Uploads API

Uploads

Uploads are files that you can upload to giosg system and they are available to be used as message attachments.

When used as chat message attachments, uploaded content is only available to users which have access to conversation where they are used. Organization users are able to see list of uploaded files but can not see the actual file unless they are participating chat conversation where the uploaded content is used.

Uploads API provides link to upload file content to Giosg CDN or organizations own CDN but does not directly store file. This means that to upload file, client needs to first do POST request to Uploads API to get signed link for uploading a file. This link can then be used to upload the actual file. Returned link is only valid for given file that it was requested for. Doing upload in two parts also allows clients to implement chat message attachment so that message with attachment get's sent before the actual upload has completed. This allows the receiving client to get message faster and show place holder image. Client can then wait until the actual file is available before showing it to user.

An Upload resource has the following attributes.

Attribute Type Editable Description
id UUID read-only UUID string identifier
original_file_name string required The original file name of the uploaded file
file_size integer required Size of the uploaded file in bytes
content_type string required Content type of the uploaded file, e.g. image/jpeg.
file_hash string required Base64 encoded md5 hash from content of the uploaded file.
upload_url object read-only Object containing url where to send the upload request and also all headers that need to be appended to form data of the POST. See upload_url object below for details.
download_url string read-only Url to download the uploaded file.
organization_id UUID read-only The ID of the owner organization
created_at datetime read-only When the upload was created
updated_at datetime read-only When the upload was modified last time
created_by_user_id UUID read-only The ID of the user who created this upload
created_by_user object read-only Details of the user who created this Upload.

upload_url object fields

Attribute Type Editable Description
url string read-only Url where to make the multipart/form-data POST to.
fields object read-only Object with keys which are required to be appended to POST request for it to succeed.

Upload a new file

Upload a file by requesting link for upload and then using that link to upload the actual file content.

POST /api/v5/orgs/<organization_id>/uploads

Attribute Type Editable Description
original_file_name string required The original file name of the uploaded file
file_size integer required Size of the uploaded file in bytes
content_type string required Content type of the uploaded file, e.g. image/jpeg.
file_hash string required Base64 encoded md5 hash from content of the uploaded file.

This endpoint returns:

  • 201 if the request was successful
  • 400 if required attribute is missing from the request
  • 400 if the upload would exceed your organization's free upload storage space
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Calculate hash of file to be uploaded
const hash = new Md5();
const buffer = await new Response(fileBlop).arrayBuffer();
hash.appendByteArray(new Uint8Array(buffer));
const hashString = hash.end();
const hashBase64 = Buffer.from(hashString as string, "hex").toString("base64");

// Request upload link  for given file.
const uploadPayload = {
  content_type: fileBlop.type,
  file_size: fileBlop.size,
  original_file_name: original_file_name,
  file_hash: hashBase64,
};
const url = "https://service.giosg.com/api/v5/orgs/837f0981-02a9-49bb-9618-f926045e4641/uploads";
const uploadLinkResponse = await makeRequest("POST", url, uploadPayload);

// Build form data for upload and make the request
const formData = new FormData();
for (const [key, value] of Object.entries(uploadLinkResponse.upload_url.fields)) {
  formData.append(key, value);
}
formData.append("file", fileBlop);
makeUploadRequest("POST", formData);

List uploads

Get a paginated collection of all the uploaded files of your organization:

GET /api/v5/orgs/<organization_id>/uploads

The endpoint accepts the following GET parameters.

Parameter Type Default Description
ordering ordering created_at Ordering of results with options created_at, updated_at, original_file_name or content_type in ascending order (- for descending).
content_type string (none) If given, returns Uploads with the given content_type.

This endpoint returns:

  • 200 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Retrieve a single upload

GET /api/v5/orgs/<organization_id>/uploads/<upload_id>

This endpoint returns:

  • 200 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Delete an upload

You may delete your uploads. Their size is freed for new file uploads.

DELETE /api/v5/orgs/<organization_id>/assets/<upload_id>

NOTE: Any previous URL (the url attribute) for the asset will stop working and the files won't be available for download any more. However, this might take a while to take effect.

This endpoint returns:

  • 204 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Retrieve organization's storage information

You may check your organization's current upload storage space usage:

GET /api/v5/orgs/<organization_id>/uploads/quota

This returns an object with the following attributes:

Attribute Type Description
free_space integer Total free space for new files, in bytes
usage integer Sum of all your organization uploaded file sizes, in bytes
limit integer The maximun allowed sum of your organization uploaded file sizes, in bytes

This endpoint returns:

  • 200 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

NOTE: If you run out of storage quota, please contact our support either on our chat or by emailing to support@giosg.com.

Visitor Uploads

Visitor Uploads are files that visitors can upload to giosg system and they are available to be used as message attachments. Uploading a file does not require user permissions so it can be used by visitors.

When used as chat message attachments, uploaded content is only available to agents which have access to the conversations where they are used. Organization users are able to see a list of uploaded files but can not see the actual file unless they are participating in the chat conversation where the uploaded content is used.

Visitor Uploads API provides a link to uploaded file content to Giosg CDN or organizations own CDN but does not directly store the file.

An Visitor Upload resource has the following attributes.

Attribute Type Editable Description
id UUID read-only UUID string identifier
original_file_name string required The original file name of the uploaded file
file_size integer required Size of the uploaded file in bytes
download_url string read-only Url to download the uploaded file.
organization_id UUID read-only The ID of the owner organization
created_at datetime read-only When the upload was created
updated_at datetime read-only When the upload was modified last time
created_by_visitor_id string read-only The ID of the visitor who created this upload
is_encrypted boolean read-only Whatever the uploaded file was encrypted or not
room_id UUID read-only ID of the room in which the visitor upload belongs to or null.
encrypted_symmetric_key string read-only The encrypted symmetric key (AES) with which the file was encrypted with. This attribute is set only if is_encrypted is true, otherwise null.

Encryption

Visitor files can be encrypted similarly how chat conversations and visitor API data is encrypted.

Visitor file encryption is used if following conditions are met:

  • Encryption feature is enabled for the organization
  • room_id is provided in the upload request and is_chat_encryption_enabled is true and public_key is set for the room.

When encryption is on, whenever a new visitor file upload is created, an AES key is also generated and stored to two places. A plaintext version of the key is stored in cache with a 90-minute expiration time. Another copy of this key is encrypted with customer provided RSA public key and stored to our database.

During the file upload the generated AES key is used to encrypt file content before it gets saved to a disk. While the cached AES key exist, a request to access the file content causes it to be automatically decrypted.

When the AES key expires from Giosg cache, only way to decrypt the file content is for customers to download the file and decrypt it using their RSA private key corresponding to the RSA public key used to do the encryption.

Upload a new file

Upload a file by making POST request with multipart/form-data to the endpoint.

POST /api/v5/orgs/<organization_id>/encrypted_visitor_uploads

Attribute Type Editable Description
created_by_visitor_id string required Visitor ID of the visitor uploading the file
upload File required Actual file to upload
room_id string optional Optional room_id where the file is related to. If the given room_id has encryption enabled uploaded file will also get encrypted.

This endpoint returns:

  • 201 if the request was successful
  • 400 if required attribute is missing from the request
  • 400 if the upload would exceed your organization's free upload storage space
  • 403 if organization does not have active subscription

Successfull upload response

Attribute Type Description
id UUID UUID string identifier
original_file_name string The original file name of the uploaded file
file_size integer Size of the uploaded file in bytes
download_url string Url to download the uploaded file.
organization_id UUID The ID of the owner organization
created_at datetime When the upload was created
updated_at datetime When the upload was modified last time
created_by_visitor_id string The ID of the visitor whom created this upload
is_encrypted boolean Whatever the uploaded file was encrypted or not
room_id UUID Room where this upload belongs to.

Example code to upload file using javascript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const uploadPayload = new FormData();
uploadPayload.append("upload", file);
uploadPayload.append("room_id", "ecbeec2c-e305-44b9-a24d-1f2c153abbd0");
uploadPayload.append("created_by_visitor_id", "db5c8d321cccc110aebbbfc26952aaaa");

const encryptedUploadUrl = "https://service.giosg.com/api/v5/orgs/b3780413-a633-488b-a7ca-151d0dc07b11/encrypted_visitor_uploads";
const uploadResponse = await fetch(encryptedUploadUrl, {
  method: "POST",
  body: uploadPayload,
});

if (!uploadResponse.ok) {
  throw new Error(
    `Upload request failed (${uploadResponse.status}): ${await uploadResponse.text()}`,
  );
} else {
  const uploadData = await uploadResponse.json();
  console.log(`File uploaded and can be accessed at ${uploadData.download_url}`);
}

List visitor uploads

Get a paginated collection of all the visitor uploaded files of your organization:

GET /api/v5/orgs/<organization_id>/encrypted_visitor_uploads

The endpoint accepts the following GET parameters.

Parameter Type Default Description
ordering ordering created_at Ordering of results with options created_at, original_file_name or content_type in ascending order (- for descending).

This endpoint returns:

  • 200 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Retrieve a single visitor upload instance

Warning

This is a draft documentation and endpoint for retrieving single visitor upload instance is not yet publicly available!

GET /api/v5/orgs/<organization_id>/encrypted_visitor_uploads/<upload_id>

This endpoint returns:

  • 200 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Retrieve a uploaded file content

GET /api/v5/orgs/<organization_id>/visitor_uploads/<upload_id>/download

Download url for visitor upload can be obtained by making a GET request to /api/v5/orgs/<organization_id>/encrypted_visitor_uploads to list previous visitor uploads or by getting a single instance: Retrieve a single visitor upload instance.

File content can be retrieved by making GET request. HTTP response will have custom header X-Giosg-Decrypted which indicates if the file was automatically decrypted by Giosg in case it was encrypted when uploading. Header X-Giosg-Decrypted is set to true if the file is decrypted and false if it needs to be encrypted by customer before using.

This header can be used to decide if the file needs encryption if programmatically proccessing visitor uploaded files.

This endpoint returns:

  • 200 if the request was successful
  • 404 if the file does not exist

Delete an upload

Warning

This is a draft documentation and endpoint for deleting single visitor upload instance is not yet publicly available!

You may delete your uploads. Their size is freed for new file uploads.

DELETE /api/v5/orgs/<organization_id>/encrypted_visitor_uploads/<upload_id>

This endpoint returns:

  • 204 if the request was successful
  • 401 if you are not authenticated
  • 403 if you do not have active subscription
  • 403 if you do not have access to the organization

Example of downloading and decrypting an visitor upload

Example on how to decrypt the visitor upload after AES key has expired from Giosg cache.

  1. Download the file. Use visitor upload list API to find download_url of the file. Path can can also be obtained through chat history if the file was used as attachment for example.
  2. It is recommended to check X-Giosg-Decrypted custom header value while downloading the file. If the value is true then the file was automatically decrypted by Giosg because the AES key had not expired or the file was not encrypted in the first place. No further processing is needed in this case.

Encrypted file content will look similar to this:

1
2
3
4
5
MDAwMDB+/gub0HVPN8sSSaXVCaebuAp2UittcV+aEuMhuQh/sqjS0kE+kPb3W4nQjkG85WDf9r8O
+XwlPQ+0saFjd7MYLerOpnQP/ibrnX4NbmWRUaRjiwbF6M+cO4OcZ1Wpdhfz+zVbH+W694kO0KHZ
mS7zOS1U2XVZbxUIElLH+TmbAuu/LIqxS7xsfRAD5WIf3LGkiA1fqrtRfz6jiWHsG1e4n5Q+wEcQ
slLj8xEEqFgV6c0NkpV6cZeppG1FDqbBDM9dmjFSF5VUx2Rh53/NwTyZoIWbZahtDR9KyOVW0/4e
....
  1. Obtain encrypted_symmetric_key corresponding for the file through visitor upload list API response or visitor upload retrieve API.
  2. Use below example Python script to decrypt the file. Decryption can be done with other programming languages but Giosg provides Giosg Crypter package to help with decrypting.

Replace encrypted_symmetric_key, path_to_private_key and encrypted_file_path with actual values and run the script. Script requires Python 3.8.0 or newer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python

import subprocess
import base64
from giosg.crypter import AESKey, asymmetric_decrypt, symmetric_decrypt

# Obtained from the listing API response or from single upload instance retrieve API
encrypted_symmetric_key = "mQXdTFOJop77e2bbBCA1E1xOcQzeBAtEDCYjwV3..."

# Load private key, this needs to match the public key used to encrypt the file.
path_to_private_key = './test_keys_for_encryption/private.pem'
private_key = subprocess.check_output(['openssl', 'rsa', '-in', path_to_private_key])

# NOTE: If your private key has passphrase you can prevent the prompt for password by passing in the "-passin" argument but
# remember to keep the passphrase safe and secret!
# pass_phrase = "ssecretpass"
# private_key = subprocess.check_output(['openssl', 'rsa', '-in', path_to_private_key, '-passin', f"pass:{pass_phrase}"])

# Decrypt the AES key using private key
json_aes_key = asymmetric_decrypt(private_key, encrypted_symmetric_key)
aes_key = AESKey.from_json(json_aes_key)

# Open encrypted file, decrypt it and write it to another file.
# You can get the original file name from "original_file_name" field if needed.
encrypted_file_path = "./encrypted_picture.jpeg"
with open(encrypted_file_path, "rb") as encrypted_file:
    enrypted_content = encrypted_file.read().decode("utf-8")
    decrypted_content = symmetric_decrypt(aes_key, enrypted_content)
    binary_content = base64.decodebytes(bytes(decrypted_content, "utf-8"))

    with open("./decrypted_picture.jpeg", "wb") as decrypted_file:
        decrypted_file.write(binary_content)