Sunshine Workflows

Important: The Sunshine Workflows API is in early access. This API is subject to change and should not be used in a production environment. Visit the Sunshine Workflows API EAP forum to provide feedback.

Introduction

A Sunshine workflow is a series of tasks performed in sequence to automate procedures in your Zendesk account. The tasks can interact with Zendesk resources such as tickets, custom objects, and more.

Workflows are represented by workflow definitions, which are JSON objects that contain all the relevant information about what work needs to be done and what data is necessary to complete that work.

To learn more, see Workflow API developer guide.

Sunshine Workflows Schema

The Sunshine Workflows service requires that every workflow definition adhere to a schema that mandates certain requirements. Various fields must be given values; others must have values of a certain type. This section details the expectations of the schema and explores its restrictions in more depth.

Global Required Fields

Global required fields are the top-level fields of a workflow definition that must be given a value. At present, these include the name, description, and tasks fields. Note that for a task, the workflow-level name field is called key to emphasize the uniqueness requirement at the task-level.

name - String

The name of your workflow must be provided. For tasks within the same workflow, each task's key field must be a unique string.

Note: name is mandatory for workflows & key is mandatory for tasks.

description - String

A short description of your workflow for you and your team to reference.

tasks - List

Contains a list of tasks. The tasks will execute from top to bottom. The (choice)[#choice] task is an exception though, allowing you to navigate the execution to a path in the workflow.

Global Optional Fields
input - Object

The input field can provide global data for the workflow. The values provided in the initial definition will be available upon every execution of the workflow. However, these values can be overridden by execution input.

inputSchema - Object

If one of your tasks requires input (for example, the ID of a custom object or the description for a new ticket), you may define a schema in the inputSchema field of the definition body. If you do so, structure your schema based on draft 7 of the Json Schema Standard. When executing the workflow, Symphony will validate the execution input based on the (Json Schema Draft 7) input schema that was provided in the workflow definition.

If an inputSchema was provided, during execution, provide valid input that matches the schema.

You can also get the schema using the workflow definition schema endpoint. This can be helpful to use in conjunction with validator clients like json-validator which will allow you to validate your workflows before sending requests to Symphony.

Required Task Level Fields
key - String

A name given to the task. Note the key must be unique in the context of the entire workflow.

type - String

The type of task to execute. Must be one of the following:

input - Object

The input given to an individual task. Note The input field inside a task object functions differently from the input field at the top-level of the workflow definition. Think of the top-level input field as a staging area, a place to organize and centralize the different contextual information your workflow will need to execute properly. The task-level input field is a consumer of this staging area: it references the various key-value pairs and uses their values in the tasks' execution. To reference a value passed as input to the workflow from a task object, use the previously mentioned string interpolation syntax "${ ... }".

Optional Task Level Fields
description - String

A short description of your task for you and your team to reference.

optional - Boolean

This boolean value can be set for any task in the workflow. If set to true, the task failure will not interrupt the workflow execution. Defaults to false.

Support Tasks

Create a Support Ticket

When creating a Support ticket, the required fields are input and type. The value for type must be set to equal CREATE_SUPPORT_TICKET and the input field must contain, at minimum, a ticket object that has values for subject, description, and any one of requester_id and requester. The requirements for the ticket object come from the Support Ticket API.

The following example task defines a task named create_ticket of type CREATE_SUPPORT_TICKET, which tells Sunshine Workflows what fields to expect. The description is set to "Create a support ticket for the refund request," which can aid coworkers in understanding the purpose of an existing workflow task. Finally, as discussed above, the input field has the required ticket object with subject, description, and requester. Note that the requester object can be optionally replaced with the requester_id of the requester.

{
  "key": "create_ticket",
  "type": "CREATE_SUPPORT_TICKET",
  "description": "Create a support ticket for the refund request.",
  "input": {
    "ticket": {
      "subject": "New refund requested for test user",
      "description": "hello world",
      "requester": {
        "name": "test user",
        "email": "[email protected]"
      }
    }
  }
}
Update a Support Ticket

When updating a Support ticket, the required fields are input and type. The value for type must be UPDATE_SUPPORT_TICKET and the input field must contain, at minimum, a ticket object as well as a ticket_id field. The requirements for the ticket and ticket_id come from the Support Ticket API.

The following example task defines a task named update_ticket of type UPDATE_SUPPORT_TICKET, which tells Sunshine Workflows what fields to expect. The description is set to "Update a support ticket for the refund request," which can aid coworkers in understanding the purpose of an existing workflow task. The ticket_id field is set to "1" which means this task will set the status of the ticket with id = "1" to solved.

{
  "type": "UPDATE_SUPPORT_TICKET",
  "key": "update_ticket",
  "description": "Update support ticket for the refund request.",
  "input": {
    "ticket_id": "1",
    "ticket": {
      "status": "solved"
    }
  }
}
Read a Support Ticket

To read a Support ticket, the required task fields are type and input, where the value of type must be READ_SUPPORT_TICKET and the input object must, at minimum, contain a ticket_id field that identifies the ticket to be read from your Zendesk instance.

In the example below, a task named read_ticket of type READ_SUPPORT_TICKET is defined to read the ticket with id = "1".

{
  "type": "READ_SUPPORT_TICKET",
  "key": "read_ticket",
  "description": "Read support ticket for refund request.",
  "input": {
    "ticket_id": "1"
  }
}
Create a Side Conversation

For a task that creates a side conversation, the required fields are type and input, where the value of type must be CREATE_SIDE_CONVERSATION and the value of input must, at minimum, contain a message object. The message object defines the content and the recipient of the side conversation, where its only required field is the to array, which holds a list of objects representing recipients, each with two fields: name and email. To learn more, visit the Side-Conversation docs.

The following example demonstrates a task named foo_create_side_conversation of type CREATE_SIDE_CONVERSATION. The input field contains the mandatory message object, which names a single recipient by the name of Sunshine Workflows with the email address [email protected]. This recipient will receive an email with the subject foo subject containing a body consisting of foo body in plain text.

{
  "type": "CREATE_SIDE_CONVERSATION",
  "key": "foo_create_side_conversation",
  "input": {
    "message": {
      "to": [
        {
          "name": "Sunshine Workflows",
          "email": "[email protected]"
        }
      ],
      "body": "foo body",
      "format": "PLAIN",
      "subject": "foo subject"
    }
  }
}

Sunshine Tasks

Update a Custom Object

To update a custom object, create a task with the type field set to UPDATE_CUSTOM_OBJECT. Then, populate the input object with two values, object_id, which identifies the target of the update, and data which contains the updated information. Per the Sunshine API, updating a custom object record is a PATCH request. Therefore, the contents of the data field are only required to contain the fields you wish to update (not the entire object).

The following example demonstrates a task named foo_update_custom_object of type UPDATE_CUSTOM_OBJECT.

{
  "type": "UPDATE_CUSTOM_OBJECT",
  "key": "foo_update_custom_object",
  "input": {
    "object_id": "foo_update_custom_object_id",
    "data": {
      "attributes": {
        "key": "value"
      }
    }
  }
}
Create a Sunshine Resource

The Sunshine Workflows Service supports the creation of many different data types that exist under the Sunshine API's umbrella. Rather than impose the need to use separate task types for each form of Sunshine data, Sunshine Workflows provides a singular CREATE_SUNSHINE_RESOURCE task. For all tasks that create a custom object, an event, a profile, or a relationship, the type field must be set to CREATE_SUNSHINE_RESOURCE. Across the different Sunshine data types, the input object has varying requirements.

  • Create a Custom Object For the creation of a custom object, the input object draws its required fields directly from the Sunshine API. The input object must contain two top-level keys named sunshine_type, with a value of CUSTOM_OBJECT, and data, where the value of data is an object with two fields, type and attributes. The first of these, input.data.type, corresponds to the type of custom object you are attempting to instantiate. The second, input.data.attributes, contains the data you wish to store in this custom object, where the fields must adhere to the schema pertaining to this object type. To learn more, visit the Sunshine API directly.

    • In the below example, the task named create_foobar_object creates a brand new custom object record of the predefined type foobar, whose schema requires only a single mandatory field named key. In the input.data.attributes object, the key field is assigned to equal 123. Additionally, this task uses the external_id field, which is a unique identifier for the object that is usually sourced from an existing data store that contains this object.
{
  "type": "CREATE_SUNSHINE_RESOURCE",
  "key": "create_foobar_object",
  "input": {
    "sunshine_type": "CUSTOM_OBJECT",
    "data": {
      "type": "foobar",
      "external_id": "foo_external_id",
      "attributes": {
        "key": "123"
      }
    }
  }
}
  • Create a Sunshine Event To create a Sunshine event, the input object must contain three top-level fields, namely, sunshine_type, which has a value of EVENT, profile, and event. profile and event are specified in the Sunshine API.

    • In the following example, the task named create_foobar_event creates a Sunshine event of the predefined type foobar, where the source is set to "symphony". In the properties object, a field called foo is assigned a value of bar which could be some relevant event metadata.
{
  "type": "CREATE_SUNSHINE_RESOURCE",
  "key": "create_foobar_event",
  "input": {
    "sunshine_type": "EVENT",
    "profile": {
      "source": "support",
      "identifiers": {
        "email": "[email protected]"
      }
    },
    "event": {
      "type": "foobar",
      "source": "symphony",
      "properties": {
        "foo": "bar"
      }
    }
  }
}
  • Create a Sunshine Relationship To create a Sunshine relationship, the input object must contain two top-level fields, sunshine_type, which has a value of RELATIONSHIP, and data. The value of data must also be an object but with the requirements drawn from the Sunshine API. Specifically, data requires relationship_type, source, and target. For more information about the meaning of these terms and the values they require, visit the Sunshine API.

    • In the following example, the task named create_sunshine_rel creates a Sunshine relationship of type copier_has_many_tickets between the source entity and the target entity, each given by their respective ID's.
{
  "type": "CREATE_SUNSHINE_RESOURCE",
  "key": "create_sunshine_rel",
  "input": {
    "sunshine_type": "RELATIONSHIP",
    "data": {
      "relationship_type": "copier_has_many_tickets",
      "source": "1c771ee0-2c3f-11e7-bf60-e5c3f630b5aa",
      "target": "35437746"
    }
  }
}
  • Create a Sunshine Profile To create a Sunshine profile, the input object must contain two top-level fields, sunshine_type, which has a value of PROFILE, and profile. The required fields of profile are drawn from the Sunshine API. Specifically, profile requires source and identifiers, where source denotes the product or service associated with the profile (such as "support" or "Amazon") and identifiers is an object containing potentially many user identities.

    • In the following example, the task named create_sunshine_prof creates a Sunshine profile associated with a user of a video game news website called foo_gaming, which is given as the source. Additionally, the identifiers field is set to contain various usernames associated with this user, as well as an email. Finally, to provide the most relevant news, the profile stores the favorite_genre of the user.
{
  "type": "CREATE_SUNSHINE_RESOURCE",
  "key": "create_sunshine_prof",
  "input": {
    "sunshine_type": "PROFILE",
    "profile": {
      "source": "foo_gaming",
      "identifiers": {
        "playstation_network_username": "johnDoe123",
        "xbox_live_username": "johnDoe_sntLose456",
        "email": "[email protected]"
      },
      "attributes": {
        "favorite_genre": "sports/soccer"
      }
    }
  }
}
Read a Sunshine Resource

The Sunshine Workflows Service supports reading from many different data types that exist under the Sunshine API's umbrella. Rather than impose the need to use separate task types for each form of Sunshine data, Sunshine Workflows provides a singular READ_SUNSHINE_RESOURCE task. For all tasks that read a custom object, an event, or a profile, the type field must be set to READ_SUNSHINE_RESOURCE. Across the different Sunshine data types, the input object has varying requirements.

Note: The return value of these tasks differs depending on what Sunshine resource is being retrieved. For example, custom objects are returned as such: json { "data": [ { "id": "14c6c4be-cb64-4678-ba73-296e3d2c32cf", "type": "product", "type_version": 1, "external_id": "3", "attributes": { "id": "3", "name": "Strawberry Chewing Gum" }, "created_at": "2017-01-03T12:35:45Z", "updated_at": "2017-01-03T12:35:45Z" } ], "errors": [ { "code": "BadRequest", "status": "400", "title": "Bad Request", "detail": "id 4 is not a valid type 1 UUID" } ] } Make sure you are pointing to the correct item in the response body:

${read_sunshine_resource_task.output.response.body.data[0]}

  • Read a Custom Object To read a custom object, the input object requires two top-level fields, sunshine_type, which must have a value of CUSTOM_OBJECT, and filters, which must be a non-empty object containing at least one field to filter the objects. These filters are used to query the Sunshine custom object API and as such, the possible options for filtering are drawn from the JSON format given by the Sunshine API.

    • In the following example, the task named foo_read_custom_object reads custom objects, filtering for the following IDs:
    • foo_read_custom_object_id_1
    • foo_read_custom_object_id_2
{
  "type": "READ_SUNSHINE_RESOURCE",
  "key": "foo_read_custom_object",
  "input": {
      "sunshine_type" : "CUSTOM_OBJECT",
      "filters": {
        "ids": "foo_read_custom_object_id_1, foo_read_custom_object_id_2"
      }
  }
}
  • Read a Sunshine Event To read a Sunshine event, the input object requires two top-level fields, sunshine_type, which must be set to EVENT, and filters, which must be a non-empty object containing at least one field to filter the events. These fields are used to query the Sunshine event API and as such, the possible options for filtering are drawn from both the event JSON format and the profile JSON format, since it is possible to retrieve events associated with a given profile or profiles. For more information, refer to the Sunshine API.

    • In the following example, the task named read_sunshine_event reads all Sunshine events associated with a profile, using the Sunshine identifier query syntax to filter the results.
{
  "type": "READ_SUNSHINE_RESOURCE",
  "key": "read_sunshine_event",
  "input": {
     "sunshine_type" : "EVENT",
     "filters": {
       "identifier": "support:user_id:361959350832"
    }
  }
}
  • Read a Sunshine Profile To read a Sunshine profile, the input object requires two top-level fields, sunshine_type, which must be set to PROFILE, and filters, which must be a non-empty object containing at least one field to filter the profiles. This corresponds to the action dubbed Retrieve a Profile in the Sunshine API. Hence, the filter object must contain a single field, namely, identifier, where the value must conform to the identifier query syntax.

    • In the following example, the task named read_sunshine_prof reads a Sunshine profile using the identifier query syntax to filter on source = shopify and user_id = 361959350832.
{
  "type": "READ_SUNSHINE_PROFILE",
  "key": "read_sunshine_prof",
  "input": {
     "sunshine_type" : "PROFILE",
     "filters": {
       "identifier": "shopify:user_id:361959350832"
     }
  }
}

System Tasks

These types of tasks do not map to a specific Zendesk entity action, but rather allow for implementing behaviors that are customized to your application's business logic.

Choice

A choice task allows for the evaluation of an expression using JavaScript syntax in the condition field. The domain of possible output values for the condition expression must be accounted for in the choices field, where each option has a corresponding list of tasks that form a subworkflow. This subworkflow is executed in the event that its key is the output of the condition expression.

  • GraalVM The GraalVM JavaScript Engine, built by Oracle Labs, is used to interpret the JavaScript syntax given in the condition field. The engine supports full compatibility with the latest ECMASCRIPT specification. Therefore, the syntax used must conform to this version.

  • Schema The choice task requires three fields, type, condition, and choices. As expected, the type field must be set to CHOICE. The condition field must be a string containing valid JavaScript that conforms to the GraalJS engine's syntax. Finally, the choices field must be an object, holding key-value pairs that map all possible output values of the condition expression (keys) to lists of tasks (values). Note that the tasks in these lists must conform to the same schema as any standalone Symphony workflow task.

  • Condition The condition field takes a JavaScript expression. This expression must resolve to a value that can be mapped to one of the keys in the choice field.

For example, given this input: json "input": { "refund_amount": "${workflow.input.amount}" }

The following expressions are valid:

    // ternary expression
    condition: "$.refund_amount > 50 ? 'a' : 'b'"
    // if...else expressions are valid. The last line in each branch is the return value
    condition: "if ($.refund_amount > 50) { 'a' } else { 'b' }"
    // Same as above, with a simple usage of variables
    condition: "if ($.refund_amount > 50) { let variable_a = 'a'; variable_a } else { let variable_b = 'b'; variable_b }"

Note that these are not function expressions and therefore no return statement is necessary (in fact, including a return statement is invalid syntax and will result in an error).

If there is a need to declare more complex behaviors as functions, remember to invoke the function otherwise the expression will not be valid. For example, the following are valid function declarations and invocations: json condition: "function evaluate() { if ($.refund_amount > 50) { let variable_a = 'a'; return variable_a } else { let variable_b = 'b'; return variable_b } } evaluate();"

    condition: "(function() { if ($.refund_amount > 50) { let variable_a = 'a'; return variable_a } else { let variable_b = 'b'; return variable_b } })()"
  • Example

The following example illustrates a simple choice task where the input to the workflow contains a refund_amount. If this amount is greater than $50, the condition returns ticket_pending; otherwise it returns ticket_solved. If ticket_solved, the Support ticket with id = 1 will have its status updated to solved, presumably because the amount is small enough that an automatic refund can be processed. If ticket_pending, the ticket will have its status updated to pending, since a larger amount may require an authorization.

{
  "type": "CHOICE",
  "key": "choice",
  "condition": "if ($.refund_amount > 50) { 'ticket_pending'; } else { 'ticket_solved'; }",
  "input": {
    "refund_amount": "${workflow.input.amount}"
  }
  "choices": {
    "ticket_solved": [
      {
        "type": "UPDATE_SUPPORT_TICKET",
        "key": "update_ticket_again",
        "input": {
          "ticket_id": "1",
          "ticket": {
            "status": "solved"
          }
        }
      }
    ],
    "ticket_pending": [
      {
        "type": "UPDATE_SUPPORT_TICKET",
        "key": "update_ticket_again",
        "input": {
          "ticket_id": "1",
          "ticket": {
            "status": "pending"
          }
        }
      }
    ]
  }
}
Lambda

A lambda task allows you to transform data in the workflow. This allows you to run evaluations in order to calculate new values that can be used in other steps of the workflow.

Place evaluations within the script field. Anything that returns a value within the body of a JavaScript function declaration will be valid.

How does script differ from the condition in a choice task? The choice task's condition takes a JavaScript expression. However, the lambda task's script field takes the body of a function declaration.

Therefore, the following script will work: "script": "if (($.refund_amount * 2) > 50) { return { resultValue: 'Expensive request' } } else { return { resultValue: 'Cheap request' } }"

Since the script evaluates the body of a function declaration, you can declare variables on their own lines (separated by semicolons): "script": "let max = 50; if (($.refund_amount * 2) > max) { return { resultValue: 'Expensive request' } } else { return { resultValue: 'Cheap request' } }"

Unlike the choice task's condition, a one-line expression like a ternary expression is not valid: "script": "(($.refund_amount * 2) > 50) ? ({ resultValue:'Expensive request' }) : ({ resultValue:'Cheap request' })"

Example

The following example illustrates a lambda task where the input to the lambda task contains a refund_amount. The lambda task calculates the double of this refund_amount. If this result is greater than 50, the lambda's script returns { resultValue: 'Expensive request' }; otherwise it returns { resultValue: 'Cheap request' }. The resulting value can be accessed in further workflow tasks with ${lambda_task_key.output.result.resultValue}.

{
  "name": "12345_refund_flow",
  "description": "Workflow with a lambda task",
  "tasks": [
    {
      "type": "LAMBDA",
      "key": "lambda_task_key",
      "input": {
        "refund_amount": 30
      },
      "script": "if (($.refund_amount * 2) > 50) { return { resultValue: 'Expensive request' } } else { return { resultValue: 'Cheap request' } }"
    },
    {
      "type": "CREATE_SUPPORT_TICKET",
      "key": "create_ticket",
      "input": {
        "ticket": {
          "subject": "New refund requested - ${lambda_task_key.output.result.resultValue}",
          "description": "foo",
          "requester": {
            "name": "test user",
            "email": "[email protected]"
          }
        }
      }
    }
  ]
}
Pause

A pause task is a mechanism for introducing the outside world into the context of your running workflow. When a pause task is executed within a workflow, it logically pauses the running workflow and waits for something to resume it. Once resumed, the remainder of the workflow executes as it normally would.

  • Timeout The timeout field on the pause task corresponds to the amount of time the task is allowed to wait before it is deemed to be in a failure state. The timeout is given in terms of seconds and if omitted for a pause task, a default timeout value of 5 minutes is assigned. Additionally, the Sunshine Workflows API imposes a 72-hour ceiling on the timeout of a pause task. If any larger number is given, 72 hours will replace the larger value.

  • Schema For a pause task, the type field must be set to PAUSE. timeout is an optional field which will be given a default value if one is not provided.

    • In the following example, a timeout of 300 seconds is provided. If no external action is taken within this time frame, the workflow will fail.
  • Resume input A pause task can be resumed with specific input for future tasks to make use of. For more details, go to the resume running workflow endpoint.

{
  "type": "PAUSE",
  "key": "Wait for approval",
  "description": "Wait for a manager's approval before proceeding",
  "timeout": 300
}

Sunshine Workflows APIs

Post New Workflow Definition

POST /api/sunshine_workflows/workflows

Using the post endpoint, you can create a new workflow by providing all of its tasks. Posting a new workflow will not invoke it. To execute the workflow, use the execute endpoint.

Example request body:

{
  "name": "create-ticket-test",
  "description": "Refund approval for Z1",
  "tasks": [
    {
      "key": "create_ticket",
      "type": "CREATE_SUPPORT_TICKET",
      "description": "Create a support ticket for the refund request.",
      "input": {
        "ticket": {
          "subject": "New refund requested for test user",
          "description": "hello world"
        }
      }
    },
    {
      "type": "READ_SUNSHINE_RESOURCE",
      "key": "read_custom_object",
      "description": "Read Custom Object Based on UUID",
      "input": {
          "sunshine_type" : "objects/records",
          "ids": "${workflow.input.object_id}"
      }
    },
    {
      "key": "create_ticket_with_co",
      "type": "UPDATE_SUPPORT_TICKET",
      "description": "create ticket with custom object",
      "input": {
        "get_id_from_task": "${create_ticket.output.response.body.ticket.id}",
        "ticket_id": "",
        "ticket": {
          "subject": "custom object ticket",
          "description": "${read_custom_object.output.response.body.data}"
        }
      }
    }
  ]
}

Example response:

HTTPStatusCode: 201

{
  "id": "d3fb7ef8-92d3-11e9-95ac-0f81bfd8ba3e"
}
Get Workflow Definition by ID

GET /api/sunshine_workflows/workflows/<workflow-id>

Access to the workflow definition is made via the unique ID.

Example response:

HTTPStatusCode: 200

{
  "name": "create-ticket-test",
  "description": "Refund approval for Z1",
  "tasks": [
    {
      "key": "create_ticket",
      "type": "CREATE_SUPPORT_TICKET",
      "description": "Create a support ticket for the refund request.",
      "input": {
        "ticket": {
          "subject": "New refund requested for test user",
          "description": "hello world"
        }
      }
    }
  ]
}
Get Workflow Definitions by Account

GET /api/sunshine_workflows/workflows

Default GET endpoint for workflows returns all workflows associated with an account.

Example response:

HTTPStatusCode: 200

{
  "workflows": [
    {
      "name": "create-ticket-test",
      "description": "Refund approval for Z1",
      "tasks": [
        {
          "key": "create_ticket",
          "type": "CREATE_SUPPORT_TICKET",
          "description": "Create a support ticket for the refund request.",
          "input": {
            "ticket": {
              "subject": "New refund requested for test user",
              "description": "hello world"
            }
          }
        }
      ]
    },
    {
      "name": "update-ticket-test",
      "description": "Update ticket for Z1",
      "tasks": [
        {
          "key": "update_ticket",
          "type": "UPDATE_SUPPORT_TICKET",
          "description": "Update a support ticket for the refund request.",
          "input": {
            "ticket_id": "${workflow.input.ticket_id}",
            "ticket": {
              "subject": "Updated user information",
              "description": "updated description of issue"
            }
          }
        }
      ],
      "meta": {
              "created_at": "1565808600870",
              "updated_at": "1565808600870"
       }
    }
  ]
}
Update Workflow Definition

PUT /api/sunshine_workflows/workflows/<workflow-id>

Example request body:

HTTPStatusCode: 200

{
  "name": "12345_z1_approval",
  "description": "Read ticket and choose",
  "tasks": [
    {
      "type": "READ_SUPPORT_TICKET",
      "key": "read_ticket",
      "description": "Read support ticket for channel.",
      "input": {
        "ticket_id": "${workflow.input.ticket_id}"
      }
    },
    {
      "type": "CHOICE",
      "key": "check for twitter",
      "condition": "if ($.channel == 'twitter') { 'twitter' } else { 'other' }",
      "input": {
        "channel": "${read_ticket.output.response.body.data.channel}"
      },
      "choices": {
        "twitter": [
          {
           "type": "UPDATE_SUPPORT_TICKET",
           "key": "update_ticket_true",
           "input": {
            "ticket_id": "${workflow.input.ticket_id}",
            "ticket": {
              "description": "twitter ticket",
              "priority": "low"
            }
           }
          }
        ],
        "other": [
          {
           "type": "UPDATE_SUPPORT_TICKET",
           "key": "update_ticket_false",
           "input": {
            "ticket_id": "${workflow.input.ticket_id}",
            "ticket": {
              "description": "not a twitter ticket",
              "priority": "low"
            }
           }
          }
        ]
      }
    }
  ]
}
Delete Workflow Definition

DELETE /api/sunshine_workflows/workflows/<workflow-id>

Example response:

HTTPStatusCode: 204

{}
Execute a Workflow

POST /api/sunshine_workflows/workflows/<workflow-id>/execute

Once a workflow is created in you can execute it anytime by using this endpoint. The execute endpoint takes in the input json, which can be used to supply values for the workflow inputSchema previously defined during creation.

For example, if you created a workflow by specifying the inputSchema to have the ticket_id as a string, then during execution, you can pass in a value for this particular param.

Example inputSchema in the context of a workflow: ```json

{ "name": "create-ticket-test", "description": "Refund approval for Z1", "inputSchema": { "type": "object", "required": [ "ticket_id" ], "properties": { "ticket_id": { "type": "string" } } }, "tasks": [ { "name": "update_ticket", "type": "UPDATE_SUPPORT_TICKET", "description": "update a new ticket", "input": { "ticket": { "subject": "changing it", "description": "something is working" }, "ticket_id": "${workflow.input.ticket_id}" } } ] } ```

Example request body for the /execute endpoint:

{
  "ticket_id": "121"
}

Example response:

HTTPStatusCode: 201

{
    "workflowId": "80c900da-916c-487a-9a8f-f1c6decbd0a6",
    "workflowInstanceId": "258e2acd-c4c5-493d-b7ab-07291bd570f5"
}
Reserved fields in the execution input

Note that there are reserved fields in the execution input, including the following: * workflow-metadata

Symphony will not accept a request where any one of the above fields is one of the properties in the execution body.

Get the Workflow Schema

The schema is based on draft 7 of the JSON schema specification. Tools like this json validator can be used to verify workflows dynamically.

GET /api/sunshine_workflows/workflows/schema/definition

Example Response:

HTTPStatusCode: 200

{
    "$id": "...",
    "$schema": "...",
    "title": "Workflow",
    "type": "object",
    "required": [...],
    ...
}
Get the Status of Running Workflow

GET /api/sunshine_workflows/instances/<workflow-instance-id>/status

Once a workflow is executed, there is a workflow instance ID that is assigned to it. This endpoint exposes the status of the workflow's execution and if the workflow is currently executing, the endpoint will additionally return the current task's key, status, and identifier.

Example response

HTTPStatusCode: 200

{
  "status": "COMPLETED"
}
Resume Running Workflow

GET/POST /api/sunshine_workflows/instances/<workflow-instance-id>/resume

Sunshine Workflows allows the use of a PAUSE task that allows for pausing a workflow until some external source triggers a resume. This endpoint provides the mechanism for resuming a running workflow.

There are GET and POST endpoints available.

Example request body (for POST only):

{
  "foo": "bar"
}

Example response:

HTTPStatusCode: 201

{
  "success": "true"
}

Future tasks can see the inputted request body as the output of the PAUSE task:

  ${pause_task.output.foo} // outputs "bar"

Product limits

Limit on number of workflows & tasks

Currently the maximum number of workflows for an account is 10. Additionally, the maximum number of tasks for a given workflow is 30.

Limit on the size of a workflow

The maximum size for a posted/updated workflow is 64kb.

Rate limits

Limit on number of requests per day

We limit the number of requests from an account to 1,000 per day.

Product Access Requirements

Sunshine workflows use the following APIs, which have the following requirements:

Sunshine Workflows API Purchase Requirement
Support Enterprise Support Enterprise
Sunshine Enterprise Sunshine Enterprise
Side Conversations Collaboration Add-On

The Sunshine Workflows service will validate your usage of workflow tasks based on which products you have purchased.

Support Enterprise gives you access to the following: - CREATE_SUPPORT_TICKET - UPDATE_SUPPORT_TICKET - READ_SUPPORT_TICKET

Sunshine Enterprise gives you access to the following: - CREATE_CUSTOM_OBJECT - READ_SUNSHINE_RESOURCE - CREATE_SUNSHINE_RESOURCE - UPDATE_CUSTOM_OBJECT

The Collaboration Add-On gives you access to the following: - CREATE_SIDE_CONVERSATION

By default, you have access to the following: - CHOICE - PAUSE - LAMBDA