Resources »

Guides »

Packages »

Create a reusable set of related records in a single package

Including records in packages

In the build a new packages guide you learned that a package can include any number of records.

If you wanted to create a new ticket from the API, you would have to create several different records and link them all together: a ticket, a message, a sender, the sender’s organization, attachments, comments, etc.

With a package, you can include all of these records in a single package and define how they relate to each other. You can also use a package as a template to create new tickets by only changing a few details, like the subject and sender. This is particularly useful when combined with bots for automation.

The record object

Packages are in JSON format. At the top-level of the package object you’ll find the records key:


{
  "package": {
    "name": "Example package"
  }
  "records": []
}

This key holds an array of record objects. Each record object has two required keys:



{
  "uid": "example_uid",
  "_context": "record_type"
}


  • uid is a unique identifier for this record that can be referenced elsewhere in the package. It will be replaced with the real record ID when the package is imported.
  • _context is the type of record: attachment, comment, ticket, task, etc.

The record object can also contain any number of additional keys based on the available fields. For instance, a ticket record has keys like subject, mask, importance, etc.

Using UIDs

When you create a record like a message, it requires a ticket_id key. If you create the ticket and the message in the same package, you don’t have any idea what the ticket’s eventual ID would be.

This is the purpose of UIDs. Each UID has a placeholder in the format {{{uid.<uid-name>}}}. You can use this placeholder as the value of any key in a record object:



"records": [
  {
    "uid": "ticket_001",
    "_context": "ticket",
    "subject": "This is a new ticket"
  },
  {
    "uid": "message_001",
    "_context": "message",
    "ticket_id": "{{{uid.ticket_001}}}"
  }
]


When this package is imported, the message would be added to the ticket ticket_001 from the same package.

Cerb will handle all dependencies between UIDs for you – you don’t have to define records in any particular order. The message could be defined first and it would still be created after the ticket is created.

Custom fields

You can set a custom field by including a key with the format custom_<id>, where <id> is the ID of the custom field. These IDs can be found from Search » Custom Fields in Cerb by adding the ID column to the worklist.



{
  "uid": "example_record",
  "_context": "record_type",
  "custom_1": "Some text",
  "custom_2": 1234,
  "custom_3": ["Option 1", "Option 2"]
}


You can create links between records by including a links key in your record object. The value is an array of context:id pairs.



{
  "uid": "example_record",
  "_context": "record_type",
  "links": [
    "ticket:123",
    "org:456"
  ]
}


Examples

Let’s look at some working examples for different record types.

Ticket

This package creates a new ticket with one message. The message has both plaintext and HTML versions, and an image attachment:



{
  "package": {
    "name": "New ticket",
    "revision": 1,
    "requires": {
      "cerb_version": "8.3.2",
      "plugins": []
    },
    "configure": {
      "prompts": [],
      "placeholders": []
    }
  },
  "records": [
    {
      "uid": "ticket_new",
      "_context": "ticket",
      "group_id": "{{{default.group_id}}}",
      "bucket_id": "{{{default.bucket_id}}}",
      "subject": "This is a new ticket",
      "importance": 50,
      "status": "open",
      "created": "{{{'now'|date('U')}}}",
      "updated": "{{{'now'|date('U')}}}",
      "participants": "customer@cerb.example",
      "org": "Example, Inc."
    },
    {
      "uid": "attachment_html_part",
      "_context": "attachment",
      "name": "original_message.html",
      "mime_type": "text/html",
      "attach": [
        "message:{{{uid.message_1}}}"
      ],
      "content": "This is the <b>HTML</b> version of the message."
    },
    {
      "uid": "attachment_image",
      "_context": "attachment",
      "name": "cerby.png",
      "mime_type": "image/png",
      "attach": [
        "message:{{{uid.message_1}}}"
      ],
      "content": "data:image/png;base64,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"
    },
    {
      "uid": "message_1",
      "_context": "message",
      "ticket_id": "{{{uid.ticket_new}}}",
      "created": "{{{'now'|date('U')}}}",
      "is_outgoing": 0,
      "sender": "customer@cerb.example",
      "response_time": "0",
      "hash_header_message_id": null,
      "headers": "To: support@cerb.example\r\nFrom: customer@cerb.example\r\nSubject: This is a new ticket\r\nX-Mailer: Cerb",
      "content": "This is the plaintext version of the message.",
      "html_attachment_id": "{{{uid.attachment_html_part}}}"
    }
  ]
}


The group_id and bucket_id keys use special placeholders from the default object. You could also set these to specific ID values, or use a prompt to ask for them at import time.

The created and updated keys use scripting syntax to create a Unix timestamp for the current time.

You’ll notice on keys like org and participants on the ticket that we’re just providing values and not IDs. Cerb will figure out for you if these are new or existing records.

In the attachment records, there’s an attach key with an array of context:id pairs to link the file to. We use the placeholder for the message’s UID. You could also use a comment, or anything else.

On the HTML attachment we provide text in the content key. For the image attachment, we prefix the content with data:image/png;base64, to let Cerb know that we’re proving binary content with base64 encoding. That will be converted back into binary for us when the file is created.

In the html_message_id key on the message we link the attachment for the HTML version of the message. This is optional, and the message will just be in plaintext otherwise.

After you import the package, the ticket looks looks like: