Skip to main content

Creating a custom timeline entry

info

This recipe assumes you've already familiarized yourself with the Core API getting started, Authentication, and Error Handling pages.

Custom timeline entries are events specific to your business that represent important context when helping customers. For example:

  • Subscription changes
  • Account level changes such as email changes or password resets
  • Custom contact forms for getting in touch, bug reports, feature requests, etc.
  • Logging outages or errors, so you know when someone gets in touch if they were affected
  • Invoicing events
  • Order refunds or delivery events

In this recipe we'll be creating a refund timeline entry as seen in the screenshot:

A custom timeline entry in a customer's timeline

Getting started

Before we dive deep into making API requests we first need to build a custom timeline entry.

You can use the custom timeline entry playground to prototype an entry. In this example we'll use the "Refund processed" template.

The components that you can use in the custom timeline entry are documented in Plain UI Components and the CustomTimelineEntryComponent Union.

You'll need to replace the "customerId": "c_XXXXXXXXXXXXXXXXXXXXXXXXXX" with a real customer ID, which you can get from the Support App or by creating one.

We’ll be using the upsertCustomTimelineEntry mutation which allows to create a new custom timeline entry or update one if it exists. This mutation requires the following permissions:

  • timeline:create
  • timeline:edit

Creating a custom timeline entry

Mutation

The GraphQL mutation is the following:

mutation upsertCustomTimelineEntry($input: UpsertCustomTimelineEntryInput!) {
upsertCustomTimelineEntry(input: $input) {
result
timelineEntry {
id
customerId
timestamp {
iso8601
}
entry {
... on CustomEntry {
title
components {
... on ComponentText {
__typename
text
textSize
textColor
}
... on ComponentSpacer {
__typename
spacerSize
}
... on ComponentDivider {
__typename
spacingSize
}
... on ComponentLinkButton {
__typename
url
label
}
}
}
}
actor {
... on MachineUserActor {
machineUser {
id
fullName
publicName
}
}
}
}
error {
message
type
code
fields {
field
message
type
}
}
}
}
note

The TimelineEntry Object and Custom Entry Object have more fields you can select, but in this recipe we're only selecting a few important ones.

Variables

caution

Remember to replace c_XXXXXXXXXXXXXXXXXXXXXXXXXX with an existing customer's id.

{
"input": {
"customerId": "c_XXXXXXXXXXXXXXXXXXXXXXXXXX",
"title": "Refund processed",
"components": [
{
"componentText": {
"text": "Invoice **#1301** was refunded to customer"
}
},
{
"componentSpacer": {
"spacerSize": "XS"
}
},
{
"componentText": {
"textSize": "L",
"textColor": "SUCCESS",
"text": "**+ $413.20**"
}
},
{
"componentDivider": {
"spacingSize": "M"
}
},
{
"componentLinkButton": {
"url": "https://stripe.com",
"label": "View in Stripe"
}
}
]
}
}

Response

{
"data": {
"upsertCustomTimelineEntry": {
"result": "CREATED",
"timelineEntry": {
"id": "t_01G9F4N117KW1VDPCFB8JSM5SF",
"customerId": "c_01G8JNBQMCJ46JTR7FEB68HTN0",
"timestamp": {
"iso8601": "2022-08-02T11:21:58.055Z"
},
"entry": {
"title": "Refund processed",
"externalId": null,
"components": [
{
"__typename": "ComponentText",
"text": "Invoice **#1301** was refunded to customer",
"textSize": null,
"textColor": null
},
{
"__typename": "ComponentSpacer",
"spacerSize": "XS"
},
{
"__typename": "ComponentText",
"text": "**+ $413.20**",
"textSize": "L",
"textColor": "SUCCESS"
},
{
"__typename": "ComponentDivider",
"spacingSize": "M"
},
{
"__typename": "ComponentLinkButton",
"url": "https://stripe.com",
"label": "View in Stripe"
}
]
},
"actor": {
"machineUser": {
"id": "mu_01G8WQ1WJSRXH5C2PD5NR9TNSD",
"fullName": "Order service (Custom timeline entry)",
"publicName": "Demo Inc. Orders"
}
}
},
"error": null
}
}
}

Navigating to the customer's timeline you should also see the custom timeline entry created:

A custom timeline entry in a customer's timeline

Side effects of custom timeline entries

The upsertCustomTimelineEntry mutation exposes a couple of input fields (in upsertCustomTimelineEntryInput) which allow you to control what happens after you create a new custom timeline entry.

changeCustomerStatusToActive

See it in the API Reference.

If set to true, the customer's state will change to ACTIVE (Waiting for help). This, in turn, will trigger a notification, which you will receive if you have any of the following settings enabled:

  • notification/slack/customer_assigned_to_you/customer_status_transitioned_to_active (only if you are assigned to the customer and have personal Slack notifications enabled)
    • A customer you are assigned to is waiting for help
  • notification/slack/customer_status_transitioned_to_active (only if you have personal Slack notifications enabled)
    • Any customer starts waiting for help
  • notification/email/customer_assigned_to_you/customer_status_transitioned_to_active (only if you are assigned to the customer)
    • Any customer starts waiting for help
  • notification/email/customer_status_transitioned_to_active
    • A customer you are assigned to is waiting for help

sendCustomTimelineEntryCreatedNotification

See it in the API Reference.

If set to true, a notification will be sent to the user assigned to the customer, as long as they have either of these settings enabled:

  • notification/slack/customer_assigned_to_you/custom_timeline_entry_created (only if you have personal Slack notifications enabled)
    • A custom timeline entry with a notification is created for a customer you are assigned to
  • notification/email/customer_assigned_to_you/custom_timeline_entry_created
    • A custom timeline entry with a notification is created for a customer you are assigned to

Having full control over these two fields is useful if you create different types of custom timeline entries. For instance, you might want to get notified about submissions of a 'support form' on your website, but not when a customer's order is shipped.

It's perfectly valid to set both of these fields to true at the same time. If you do this, the customer's state will move to ACTIVE and a notification will be sent to the assigned user and/or every other user in the workspace.


If you have any problems, please get in touch with us by email on help@plain.com, and we will be happy to help.