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.
There are two different ways to upload file attachments. Direct CDN upload, or Kantata OX server 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 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"
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.
{- "attachment": {
- "type": "string",
- "direct": true,
- "data": "string",
- "filename": "string"
}
}
{- "count": 0,
- "meta": {
- "count": 0,
- "page_count": 0,
- "page_number": 0,
- "page_size": 0
}, - "results": [
- {
- "key": "string",
- "id": "string"
}
], - "attachments": {
- "property1": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}, - "property2": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}
}
}
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.
{- "attachment": {
- "filename": "string"
}
}
{- "count": 0,
- "meta": {
- "count": 0,
- "page_count": 0,
- "page_number": 0,
- "page_size": 0
}, - "results": [
- {
- "key": "string",
- "id": "string"
}
], - "attachments": {
- "property1": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}, - "property2": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}
}
}
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.
Attachment has been deleted.
Bad Request
Unauthorized request
Forbidden request
Page Not Found
Unprocessable Entity
Service is unavailable
{- "errors": [
- {
- "type": "string",
- "message": "string"
}
]
}
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.
{- "count": 0,
- "meta": {
- "count": 0,
- "page_count": 0,
- "page_number": 0,
- "page_size": 0
}, - "results": [
- {
- "key": "string",
- "id": "string"
}
], - "attachments": {
- "property1": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}, - "property2": {
- "created_at": "2019-08-24T14:15:22Z",
- "creator_name": "string",
- "deletable": true,
- "deleted_at": "2019-08-24T14:15:22Z",
- "filename": "string",
- "filesize": 0,
- "previewable": true,
- "proof_url": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "url": "string",
- "view_in_new_tab": true,
- "viewable": true
}
}
}