You can upload a file and attach it to a custom object record. The attachment appears in their own tab of the record on the Custom object records page in Zendesk Support. Admins configure whether or not attachments are allowed for a custom object. When they are allowed, you can use the Custom Object Record Attachment API to upload attachments to the record.

Custom object record attachment limitations

  • Each record can have a maximum of five attachments.
  • Each attachment must be less than or equal to 10MB in size.

Anonymous access

When an admin allows anonymous access for a custom object, anonymous users can download its attachments with the Download endpoint. The endpoint redirects to a short-lived signed URL, so a signed URL that was already issued keeps working until it expires, even if anonymous access is turned off afterwards. Anonymous users can also list a record's attachments to find their ids. Responses to anonymous requests omit created_by and the malware scan properties (malware_scan_status, malware_access_override, and malware_scan_completed_at). Uploading, updating, and deleting attachments still require authentication.

List Custom Object Record Attachments

  • GET /api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments

Lists all attachments associated with a custom object record.

Allowed For

Parameters

NameTypeInRequiredDescription
custom_object_keystringPathtrueThe key of a custom object
record_idstringPathtrueThe id of a custom object record

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments")request = Net::HTTP::Get.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "custom_object_record_attachments": [    {      "content_type": "application/pdf",      "content_url": "https://company.zendesk.com/api/v2/custom_objects/apartment/records/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download",      "created_at": "2024-01-15T14:30:00Z",      "created_by": "John Doe",      "custom_object_record_id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",      "filename": "contract.pdf",      "id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",      "malware_access_override": false,      "malware_scan_completed_at": "2024-01-15T14:31:00Z",      "malware_scan_status": "malware_not_found",      "size": 245760    },    {      "content_type": "image/jpeg",      "content_url": "https://company.zendesk.com/api/v2/custom_objects/apartment/records/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E3/download",      "created_at": "2024-01-15T14:31:00Z",      "created_by": "Jane Smith",      "custom_object_record_id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",      "filename": "floorplan.jpg",      "id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E3",      "malware_access_override": false,      "malware_scan_completed_at": "2024-01-15T14:32:00Z",      "malware_scan_status": "malware_not_found",      "size": 512000    }  ]}
400 Bad Request
// Status 400 Bad Request
{  "error": "Invalid URI endpoint"}
401 Unauthorized
// Status 401 Unauthorized
null
429 Too Many Requests
// Status 429 Too Many Requests
null

Create Custom Object Record Attachment

  • POST /api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments

Creates a new attachment associated with a custom object record. The custom object must have the "allows_attachments" setting enabled.

Allowed For

  • Agents

Parameters

NameTypeInRequiredDescription
custom_object_keystringPathtrueThe key of a custom object
record_idstringPathtrueThe id of a custom object record

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments \  -F "uploaded_data=@/path/to/file.txt" \  -H "Authorization: Bearer {access_token}" -X POST
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments"	method := "POST"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("POST", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'POST',  url: 'https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"POST",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments")request = Net::HTTP::Post.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "custom_object_record_attachment": {    "content_type": "application/pdf",    "content_url": "https://company.zendesk.com/api/v2/custom_objects/apartment/records/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download",    "created_at": "2024-01-15T14:30:00Z",    "created_by": "John Doe",    "custom_object_record_id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",    "filename": "contract.pdf",    "id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",    "malware_access_override": false,    "malware_scan_completed_at": null,    "malware_scan_status": "not_scanned",    "size": 245760  }}
400 Bad Request
// Status 400 Bad Request
{  "error": "Invalid URI endpoint"}

Update Custom Object Record Attachment for Malware

  • PUT /api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}

Updates malware access settings for the specified attachment. This is typically used to allow access to attachments that were flagged as containing malware.

Allowed For

  • Admins

Parameters

NameTypeInRequiredDescription
custom_object_keystringPathtrueThe key of a custom object
idstringPathtrueThe id of a custom object record attachment
record_idstringPathtrueThe id of a custom object record

Example body

{  "custom_object_record_attachment": {    "malware_access_override": true  }}

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id} \  -H "Content-Type: application/json" \  -d '{"custom_object_record_attachment": {"malware_access_override": true}}' \  -H "Authorization: Bearer {access_token}" -X PUT
Go
import (	"fmt"	"io"	"net/http"	"strings")
func main() {	url := "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2"	method := "PUT"	payload := strings.NewReader(`{  "custom_object_record_attachment": {    "malware_access_override": true  }}`)	req, err := http.NewRequest(method, url, payload)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""{  \"custom_object_record_attachment\": {    \"malware_access_override\": true  }}""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("PUT", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');var data = JSON.stringify({  "custom_object_record_attachment": {    "malware_access_override": true  }});
var config = {  method: 'PUT',  url: 'https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  data : data,};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requestsimport json
url = "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2"
payload = json.loads("""{  "custom_object_record_attachment": {    "malware_access_override": true  }}""")headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"PUT",	url,	headers=headers,	json=payload)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2")request = Net::HTTP::Put.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")request.body = %q({  "custom_object_record_attachment": {    "malware_access_override": true  }})response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "custom_object_record_attachment": {    "content_type": "application/octet-stream",    "content_url": "https://company.zendesk.com/api/v2/custom_objects/apartment/records/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download",    "created_at": "2024-01-15T14:30:00Z",    "created_by": "John Doe",    "custom_object_record_id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",    "filename": "potentially_malicious_file.exe",    "id": "01HQ2Z3X4Y5T6R7S8P9Q0W1E2",    "malware_access_override": true,    "malware_scan_completed_at": "2024-01-15T14:31:00Z",    "malware_scan_status": "malware_found",    "size": 1024000  }}
400 Bad Request
// Status 400 Bad Request
{  "error": "Invalid URI endpoint"}

Delete Custom Object Record Attachment

  • DELETE /api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}

Deletes the specified attachment associated with a custom object record.

Allowed For

  • Agents

Parameters

NameTypeInRequiredDescription
custom_object_keystringPathtrueThe key of a custom object
idstringPathtrueThe id of a custom object record attachment
record_idstringPathtrueThe id of a custom object record

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id} \  -X DELETE \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2"	method := "DELETE"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("DELETE", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'DELETE',  url: 'https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"DELETE",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2")request = Net::HTTP::Delete.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

204 No Content
// Status 204 No Content
null
400 Bad Request
// Status 400 Bad Request
{  "error": "Invalid URI endpoint"}

Download Custom Object Record Attachment

  • GET /api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}/download

Downloads the specified attachment content. Returns a redirect to the attachment's content URL. Access to malicious attachments is controlled by the malware_access_override setting.

Allowed For

Parameters

NameTypeInRequiredDescription
inlinebooleanQueryfalseIf true, the attachment content is displayed inline in the browser. If false or omitted, the attachment is downloaded as a file.
custom_object_keystringPathtrueThe key of a custom object
idstringPathtrueThe id of a custom object record attachment
record_idstringPathtrueThe id of a custom object record

Code Samples

Curl
curl --request GET https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download?inline= \--header "Authorization: Bearer ${authToken}" \--header "Content-Type: application/json"
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download?inline="	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download")		.newBuilder()		.addQueryParameter("inline", "");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  params: {    'inline': '',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download?inline="headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/custom_objects/car/records/01GCSJW391QVSC80GYDH7E93Q6/attachments/01HQ2Z3X4Y5T6R7S8P9Q0W1E2/download")uri.query = URI.encode_www_form("inline": "")request = Net::HTTP::Get.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end
curl - Download attachment
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}/download \  -H "Authorization: Bearer {access_token}"
curl - Display attachment inline
curl https://{subdomain}.zendesk.com/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}/download?inline=true \  -H "Authorization: Bearer {access_token}"

Example response(s)

200 OK
// Status 200 OK
null
400 Bad Request
// Status 400 Bad Request
{  "error": "Invalid URI endpoint"}
401 Unauthorized
// Status 401 Unauthorized
null
429 Too Many Requests
// Status 429 Too Many Requests
null