Kantata Kantata OX Knowledge Base
Release Notes
Status Page

Attachments

An Attachment is a file asset that is attached to another Kantata OX object. Depending on the type of object, the file is used or displayed in different ways. The objects that Attachments can be attached to are: Post, Expense, and Proof.

To create an Expense or Post with an Attachment, use the resulting attachment_id from the Attachment creation request in the parameters of the Expense or Post creation request.

Creating a new Attachment

There are two different ways to upload file attachments. Direct CDN upload, or Kantata OX server upload.

Direct CDN Upload

Uploading directly to the CDN is a three step process but allows for faster uploading, significantly larger attachments, and more accurate upload progress information.

Retrieving upload credentials has two required fields, direct and attachment. The direct field must be set to true. The attachment field must include two attributes:

  • type (required) must be post_attachment, receipt, or proof.
  • filename (required) is the filename of the file to be uploaded.

The file name must not contain spaces or special characters other than an underscore ("_") or a hyphen ("-"), otherwise the file upload will fail.

After successfully creating an attachment, an upload url and credentials will be returned in JSON format with an HTTP 200 status code.

curl --form "direct=true" --form "attachment[filename]=attachment.doc"
--form "attachment[type]=post_attachment" "https://api.mavenlink.com/api/v1/attachments.json"

The response JSON will then contain the information to upload the file:

{
   "id": 2,
   "action": "[upload url]",
   "fields":{
      "utf8": "✓",
      "key": " ... ",
      "Content-Disposition": "attachment; filename="attachment.doc"; filename*=UTF-8''attachment.doc",
      "success_action_status": 201,
      "AWSAccessKeyId": " ... ",
      "acl": "private",
      "policy": " ... ",
      "signature": " ... "
   }
}

A second POST request can then be made to the provided action with the field values returned in the JSON response, in addition to the file data. The AWSAccessKeyId field value is only active for 5 seconds, so these consecutive calls are meant to be made in quick succession via a script.

Other than $file, variables in the request that start with $ are the values represented by the " ... " blanks in the JSON response.

curl -X POST "[upload url]" -H 'cache-control: no-cache' --form 'AWSAccessKeyId='$awsKey --form 'Content-Disposition="attachment; filename="$file"; filename*=UTF-8''''''$file"' --form 'x-amz-server-side-encryption=AES256' --form 'key='$key --form 'policy='$policy --form 'signature='$sig --form 'acl=private' --form 'success_action_status=201' --form 'utf8=✓' --form 'file=@'$file

Finally, once the upload has completed successfully, a 'sync' request (specified below) is necessary to mark the upload as complete.

Below is a simplified example using ruby to achieve the same thing as with the curl commands above:

#!/usr/bin/env ruby

require 'net/https'
require "uri"
require 'json'

TOKEN="Bearer <your-secret-here>"
ATTACHMENTS_ENDPOINT="https://api.mavenlink.com/api/v1/attachments.json"
BOUNDARY = "AaB03x" # Make sure it is not present in the file you're uploading.

file = ARGV[0]
filename = File.basename(file)

uri = URI.parse(ATTACHMENTS_ENDPOINT)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Authorization'] = TOKEN
request.set_form_data(first_request_params)
response = http.request(request)
first_response = JSON.parse(response.body)

# for the second request we manually build the request body
post_body = []

second_request_params = first_response["fields"].merge({ "file" => File.open(file) })
second_request_params.each do |k,v|
  post_body << "--#{BOUNDARY}\r\n"
  if v.is_a?(IO)
    post_body << "Content-Disposition: form-data; name="#{k}"; filename="#{filename}"\r\n"
    post_body << "\r\n"
    post_body << File.read(file)
    post_body << "\r\n"
  else
    post_body << "Content-Disposition: form-data; name="#{k}"\r\n\r\n"
    post_body << v.to_s + "\r\n"
  end
end

post_body << "--#{BOUNDARY}--\r\n"

uri = URI.parse(first_response["action"])
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request.body = post_body.join
request["Content-Type"] = "multipart/form-data, boundary=#{BOUNDARY}"
response = http.request(request)

exit(response.code == second_request_params["success_action_status"].to_s)

Syncing a created Attachment

Syncing marks an upload as complete, and verifies its existence on the CDN.

A sync request can be made as follows:

curl -X PUT "https://api.mavenlink.com/api/v1/attachments/2/sync.json"

Kantata OX Server Upload

For small attachments (< 10MB), you may upload to our servers and skip the 3-step direct CDN upload process. Doing so requires one field, attachment, with two required attributes:

  • type (required) must be either post_attachment, receipt, or proof.
  • data (required) is the multipart/form-data encoded file contents.

After successfully creating an attachment its metadata will be returned in JSON format with an HTTP 200 status code. To upload a file using the curl utility, you would run a command like this one:

curl --form "attachment[data]=@test.rb" --form "attachment[type]=post_attachment" "https://api.mavenlink.com/api/v1/attachments.json"

This endpoint returns structured Attachment objects. As with all Kantata OX API endpoints, the returned data will be referenced in sorted order in the results array and will be indexed by ID in the attachments top-level JSON key. Please see our Response Format section for more information.

Request
Request Body schema: application/json
required
object
type
required
string

Indicates the type of Attachment within Kantata OX. Allowed values are: receipt, post_attachment, or proof. A receipt is attached to an Expense, a post_attachment is attached to a Post, and a proof is attached to a Proof.

direct
boolean

Whether or not this is a direct CDN upload. If direct is set to true, the filename field is required. If direct is set to false or is not present, the data field is required.

data
string

The multipart/form-data encoded file contents. Only used if direct is not set to true. Note that the maximum allowed size for file data uploads is 10MB. For larger files, use a direct CDN upload.

filename
string

The filename of the file to be uploaded. Only used if direct is set to true.

Responses
200

Attachment has been created.

Response Schema: application/json
count
integer <int32>
object
Array of objects
object
400

Bad Request

401

Unauthorized request

403

Forbidden request

404

Page Not Found

422

Unprocessable Entity

503

Service is unavailable

post/attachments
Request samples
application/json
{
  • "attachment": {
    }
}
Response samples
application/json
{
  • "count": 0,
  • "meta": {
    },
  • "results": [
    ],
  • "attachments": {
    }
}

Updating an existing Attachment

This endpoint returns structured Attachment objects. As with all Kantata OX API endpoints, the returned data will be referenced in sorted order in the results array and will be indexed by ID in the attachments top-level JSON key. Please see our Response Format section for more information.

Request
path Parameters
id
required
integer

The ID of the Model.

Request Body schema: application/json
required
object
filename
string

Used to rename an already existing attachment within Kantata OX.

Responses
200

Attachment has been updated.

Response Schema: application/json
count
integer <int32>
object
Array of objects
object
400

Bad Request

401

Unauthorized request

403

Forbidden request

404

Page Not Found

422

Unprocessable Entity

503

Service is unavailable

put/attachments/{id}
Request samples
application/json
{
  • "attachment": {
    }
}
Response samples
application/json
{
  • "count": 0,
  • "meta": {
    },
  • "results": [
    ],
  • "attachments": {
    }
}

Deleting an existing Attachment

Destroys an attachment from its subject object.

The response will contain no content and an HTTP 204 status code if the request was successful, or a standard Kantata OX error message explaining why the object could not be deleted.

Request
path Parameters
id
required
integer

The ID of the Model.

Responses
204

Attachment has been deleted.

400

Bad Request

401

Unauthorized request

403

Forbidden request

404

Page Not Found

422

Unprocessable Entity

503

Service is unavailable

delete/attachments/{id}
Request samples
Response samples
application/json
{
  • "errors": [
    ]
}

Sync a created attachment

Marks an upload as complete, and verifies its existence on the CDN.

This endpoint returns structured Attachment objects. As with all Kantata OX API endpoints, the returned data will be referenced in sorted order in the results array and will be indexed by ID in the attachments top-level JSON key. Please see our Response Format section for more information.

Request
path Parameters
id
required
integer

The ID of the Model.

Responses
200

Attachment has been updated.

Response Schema: application/json
count
integer <int32>
object
Array of objects
object
400

Bad Request

401

Unauthorized request

403

Forbidden request

404

Page Not Found

422

Unprocessable Entity

503

Service is unavailable

put/attachments/{id}/sync
Request samples
Response samples
application/json
{
  • "count": 0,
  • "meta": {
    },
  • "results": [
    ],
  • "attachments": {
    }
}