The Zendesk API lets you work with native objects such as tickets and users. Though you have many objects at your disposal, the available ones can't meet every possible need of every customer. Enter custom objects.
The Custom Objects API lets you define a new object type in Zendesk, then create objects from the new object type. The API stores your objects in the Zendesk infrastructure. You can also use it to define and manage relationships with other objects, including native Zendesk objects like tickets and users.
The API consists of the following resources:
- object types - templates for creating custom objects
- object records - instances of custom objects
- relationship types - templates for creating relationship records
- relationship records - instances of relationships between two object records
- jobs - batch operation jobs for object records and relationship records
Object types
An object type is a template for objects of that type. It consists of a key
attribute and a schema
attribute.
The key is the name that identifies the object type, like "ticket" or "user" in the Zendesk API.
The schema describes the data. The schema doesn't contain any information about a specific object. It just describes that information. You can also define validation rules in the schema to maintain the data integrity of your object records. For more information, see Creating a schema for a custom object.
Example:
{
"data": {
"key": "copier",
"schema": {
"properties": {
"id": {
"type": "string",
"description": "Unique identifier assigned to the copier by IT"
},
"model": {
"type": "string",
"description": "Make and model of the copier"
},
"networked": {
"type": "boolean",
"description": "Whether or not the copier is networked"
}
},
"required": ["id", "model"]
}
}
}
API path
The API path for object types is /api/sunshine/objects/types
. For details, see the API docs.
API docs
See Object Types in the API docs.
Object records
An object record is an instance of a given object type. It consists of a type
string and an attributes
object. The type is the name (or key) of any object type you defined. The attributes
object contains the attributes you defined for the object type and their values.
Example:
{
"data": {
"type": "copier",
"attributes": {
"id": "1019 4C BW",
"model": "OptiJet X55",
"networked": true
}
}
}
API path
The API path for object records is /api/sunshine/objects/records
. For details, see the API docs.
API docs
See Object Records in the API docs.
Relationship types
You can define relationships between objects to use your data in more meaningful ways. A relationship can be between:
- two custom objects
- one custom object and any of the following native Zendesk objects: tickets, users, articles, organizations, groups, or chats.
- two of the listed native Zendesk objects
The API supports three relationship types:
-
One-to-one - Both object types can have only one object on either side of the relationship. For example, a ticket would only be associated with a unique copier, and a copier would only be associated with a unique ticket. This isn't a viable option in the IT department example. The number of copier objects would have to equal the number of ticket objects.
-
One-to-many or Many-to-one - In a one-to-many relationship type, each object of the first object type relates to none, one, or many object of the second object type. For example, a copier can be associated with none, one, or many tickets. In a many-to-one relationship type, none, one, or many objects of the first object type can be associated with each object of the second object type. For example, none, one, or many tickets can be associated with a copier. This alternative perspective on the same data makes a difference on how you access your data.
-
Many-to-many - You define a many-to-many relationship type with two one-to-many relationship types. Each object of the first object type relates to none, one, or many objects of the second object type, and each object of the second object type relates to none, one, or many objects of the first object type.
A relationship type consists of the following attributes: key
, source
, and target
. The key is the name that identifies the relationship type. The source is the left-side "one" in a one-to-one or one-to-many relationship type, or the left-side "many" in a many-to-one relationship type. The target is the right-side "one" or "many". Their values can be the name of any object type you defined or any of the following names for native Zendesk object types:
- zen:ticket
- zen:user
- zen:article
- zen:organization
- zen:group
- zen:chat
- zen:brand
- zen:lead
- zen:contact
- zen:deal
The source and target can be two custom object types, a custom object type and a Zendesk object type, or two Zendesk object types, as either source or target.
To define a one-to-many relationship type, enclose the target value in square brackets. To define a many-to-one relationship type, enclose the source value in square brackets. Omit the square brackets for a one-to-one relationship type.
Defining a relationship type doesn't create an association between two specific objects. It just describes the relationship record. To associate two objects, you must create a relationship record between the two objects. See Relationship Records.
Example:
{
"data": {
"key": "copier_has_many_tickets",
"source": "copier",
"target": ["zen:ticket"]
}
}
API path
The API path for relationship types is /api/sunshine/relationships/types
. For details, see the API docs.
API docs
See Relationship Types in the API docs.
Relationship Records
A relationship record is an instance of a given relationship type. It ties two specific object records together. A relationship record consists of the ids of the two related object records and the relationship type. The record doesn't contain any actual object data -- just the ids of the object records.
Creating relationship records allows you to use the List Relationship Records by Object Record endpoint to get links to all the object records associated with a particular object. For example, a single request could return links to all the tickets associated to a particular copier.
Example:
{
"data": {
"relationship_type": "copier_has_many_tickets",
"source": "1c771ee0-2c3f-11e7-bf60-e5c3f630b5aa",
"target": "35437746"
}
}
API path
The API path for relationship records is /api/sunshine/relationships/records
. For details, see the API docs.
API docs
See Relationship Records in the API docs.
Jobs
You can use the Jobs API to define and run your own batch operation jobs for object records and relationship records. For example, you can define and run a job that creates many object records in Zendesk.
Batch operation jobs are asynchronous. Making a request kicks off the job but the API doesn't wait for the job to finish before sending a response. The response gives you a job id that you can use to poll the API for the status of the job. A job can be "queued", "processing", "failed", "completed", or "aborted".
You use a single endpoint, Create Job, for all batch operations:
POST api/custom_resources/jobs
The endpoint takes a JSON object with the following properties:
Name | Type | Comment |
---|---|---|
type | string | One of "resources" or "relationships" |
action | string | Currently only "post" is supported |
data | array | An array of object records or relationship records to process. The format is the same as the "data" object for the equivalent single-operation endpoints for object records or relationship records |
Example:
{
"type": "resources",
"action": "post",
"data": [
{
"type": "product",
"external_id": "3",
"attributes": {
"id": "3",
"name": "Strawberry Chewing Gum"
}
},
{
"type": "product",
"external_id": "4",
"attributes": {
"id": "4",
"name": "Coffee Chewing Gum"
}
}
]
}
API path
The API path for jobs is /api/custom_resources/jobs
. For details, see the API docs.
API docs
See Jobs in the API docs.
34 Comments
Can Custom Objects and Relationships be retrieved via the support app client? i.e. sidebar_client.get("relationships") or sidebar_client.request("/api/custom_resources/resources/{resource_id}/relationships/{relationship_type_key}")??
Thanks,
Mark DiValerio
Hi Mark. The interface to Custom Objects is only through REST APIs right now. There is a strong interest in having a tighter integration with the Apps framework, however, so keep an eye out in the future for changes such as this.
Hi there Mark-
As Bryan pointed out, a tighter integration with the apps framework is not available right now. That said, your second example would still work with the Zendesk Apps framework - the only option currently is using client.request().
Regards,
Joey
Is there a size limit for the data array for a job? I'm trying to bulk import ~4000 custom objects and I'm not sure if this can all be done in one job, or if there is a better way to bulk import custom objects other than via the API.
Hi Ben. The limit is a 1000. It's not documented right now but soon will be.
Thanks for the response Bryan. One more question, when inserting relationship records, can this be done with the external_ids of each object? Or does it have to be the ids generated from when created in zendesk?
Hi Ben. It's the Zendesk generated ID of the resource.
So there is no way to use the external_id?
Can you give more details on your use case Ben?
ID is the attribute that is guaranteed unique across all resource types. If you give more details maybe there's some approach that can get you what you're looking for.
Hi Ben, it sounds like you want to have external IDs in the source or target of a relationship, is that correct?
If so, this is not something that you can do currently. The workaround is to create a relationship to an object, then get the external ID from that object.
Jason,
Yes, using the external_ids in the source and target was my intent. I can do it without using them, it just would have been a nice convenience. Thank you for the response
Deleted my previous comment. Figured out the links. Now I just have this question:
How do I get more objects per page in a GET to get all of my objects of a certain type? What should the url look like?
Is this what you're looking for Ben?
You can specify up to 1000 records per page using the per_page parameter:
https://developer.zendesk.com/rest_api/docs/custom-objects-api/resources#parameters
If listing object records by object type key, you can use the following optional query string parameters:
Example:
Any way we could get the "next page" in web JSON view to link to the next and previous page? Perhaps also a page with the per_page parameter?
Thank you for your help, those suggestions were what I was looking for. Now I have another question:
When I try to delete all my object records (for testing purposes to test bulk adding them afterwards) I successfully delete all records (~4000) but one. No matter what I try I can not delete this specific record. I get the error
Invoke-RestMethod : The remote server returned an error: (412) Precondition Failed.
I'm not sure why this is happening. Any ideas?
Hi Ben. Is it that particular record or just whatever the last record is that can't be deleted? I'm thinking maybe there's a relationship with another object type that's somehow keeping that record from being deleted.
This may also be an issue that's specific to your instance and what Custom Objects is doing behind the scenes. Please enter a ticket with support@zendesk.com and we can dig into it deeper.
Bryan,
You were correct, after I deleted relationships I was able to delete all of the Object records. Thank you for all your help
Great to hear! Thanks for sharing Ben.
Hey all,
Wanted to see if there might be any plans to support a look-up by external_id on custom objects?
Use Case: We are looking to use Objects as Projects. Each project is assigned an ID internally. As project progresses, people are added and removed. Additionally we update the state of the project as well as attributes through the Lifecycle.
Currently we'd have to write back the Zendesk Object ID after creation into our own DB. If we could just perform a look-up on external id it would simplify updating as well as avoiding duplicate object creation.
Best,
Matt
@Matt Owens: I don't see this documented anywhere, but this works for me:
You have to declare the resource type with the external ID or the call will fail. I think it's set up that way because the custom resources API only enforces unique external IDs per resource type.
Thank you @Jason!
This is incredibly helpful, changes some build plans for sure!
Any hints on if/when custom objects will available via Liquid code in triggers and automations? Because that would be amazing.
Is there any need to created a 1:1 relationship between a ticket and a custom object, rather than just define the ticket ID as an attribute in the object itself?
Hi Justin,
You could certainly put a ticket ID inside the resource itself. The advantage of this is you can get the resource and ticket ID in one request. The downside is you cannot do queries for "tickets related to a resource" through Custom Objects.
Makes perfect sense, thanks Jason!
Hey,
For some reason the API schema isn't matching to my schema in sunshine
Schema from sunshine:
But then when calling the api for a record I get :
Notice the random capitalization on Subject, and the camel casing on CallToActionHeading.
Why is this? how can i resolve this?
I also get issues creating records if i try to follow the schema from sunshine rather than using capital S and camel case.
Thank you for reporting this Jonathan -- I'm looking into this and will get back to you. I'll say this is not what is expected but am trying to find out more details.
Thanks for looking into it.
I created a new object with the same parameters and it worked correctly.
I did some trouble shooting where I then edited that record so the attributes were different (using the admin interface not the api) and tried to submit a new record using the old params and it worked.
So I suspect the editing of a record structure isn't updating the expected schema everywhere correctly.
Hi Jonathan and thank you again for reporting this. It is indeed an issue, relating to the UI of the admin area as you discovered. And to confirm with your experience, going through the API does not surface the problem.
A fix is being worked on, but in the meantime, use the API. I'll try and post here when the fix is confirmed.
Is there a way for end users who are not signed in to query the sunshine objects?
From within zendesk guide we want to call the sunshine api and return some objects we've stored there.
Ive got "end_users_can_read" set to true but it seems that only applys to signed in end users, we need anyone to be able to make the api request.
I considered using an authentication token but since the only way to do that is to have that visible in our front end client and there is no way to restrict the token to just access sunshine or something like that, the solution doesn't work either.
As a work around we've created our own public API that works as a proxy to call zendesk(with hidden auth), but this isn't ideal for us and really seems silly to go from zendesk guide -> our proxy -> zendesk sunshine.
Please sign in to leave a comment.