Tray Embedded / Integration walkthrough / API calls step by step

API calls step by step

Having already created the webhook demo solution, you can now follow all the steps below.

As introduced in the main Main components diagram, these will introduce you to all the API calls necessary in order to register an End User, and allow them to click on an available solution to activate their own instance.

All of the API queries and mutations below can be run by using our Insomnia GraphQL collection (runs locally) or they can be pasted into the GraphQL playground (runs online)
  • Each API call will need the correct token (master or user) passed as a bearer. This is done largely automatically in our Insomnia collection (once you add your master token to the environment), but will need to be entered manually when using the GraphQL playground

  • You will be able to simulate an End User clicking to configure a Solution Instance by pasting the Config Wizard URL into your browser and completing the setup of a Solution Instance for that End User.

  • You will then be able to test the Solution Instance by pasting its webhook URL into your browser. As it is a webhook-triggered workflow, this will trigger a run of the End User's Workflow Instance.

  • Finally, you can then login to the Tray Embedded UI to find the End User's Solution and Workflow Instances, to see how debugging works.

Registering a user and obtaining an accessToken

The first thing to do in your application is to register a user with createExternalUser (master token):

mutation {
createExternalUser(input: {name: "Billy Bluehat", externalUserId: "96xxxxxxd7"}) {
userId
}
}

This will return the userId in the result:

{
"data": {
"createExternalUser": {
"userId": "fbb96559-xxxx-xxxx-xxxx-5552c2d2fca4"
}
}
}

The userId can then be used to create an accessToken with authorize (master token):

mutation {
authorize(input: {userId: "fbb96559-xxxx-xxxx-xxxx-5552c2d2fca4"}) {
accessToken
}
}

Result:

{
"data": {
"authorize": {
"accessToken": "0c8c8e16e39e4xxxxxxxxxxxxxxxxxxxxxx49545b584e307063710d1ee"
}
}
}

List available Solutions in your app interface

The Solutions available to your End Users can be listed using the solutions query (master token):

query {
viewer {
solutions {
edges {
node {
id
title
description
tags
customFields {
key
value
}
}
cursor
}
pageInfo {
hasPreviousPage
hasNextPage
startCursor
endCursor
}
}
}
}

Within the node of the result you will find the Solution id:

{
"data": {
"viewer": {
"solutions": {
"edges": [
{
"node": {
"id": "91c0f56f-xxxx-xxxx-xxxx-184686978ea5",
"title": "Webhook demo",
"description": "",
"tags": [],
"customFields": [],
"configSlots": [
{
"externalId": "external_slack-channel",
"title": "slack-channel",
"defaultValue": "\"CxxxxTP\""
},
{
"externalId": "external_slack-message",
"title": "slack-message",
"defaultValue": "\"The webhook for your solution instance has been triggered\""
}
]
},
"cursor": "OTFjMGY1NmYtMGE1MC00M2Y4LWExMTAtMTg0Njg2OTc4ZWE1"
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "OTFjMGY1NmYtMGE1MC00M2Y4LWExMTAtMTg0Njg2OTc4ZWE1",
"hasPreviousPage": false,
"startCursor": "OTFjMGY1NmYtMGE1MC00M2Y4LWExMTAtMTg0Njg2OTc4ZWE1"
}
}
}
}
}

Note that the above pageInfo values can be used for pagination

User clicks to create a Solution Instance

With the correct solutionId from above use createSolutionInstance (user token) to create a Solution Instance:

mutation {
createSolutionInstance(input: {
solutionId: "e2ed06d9-xxxx-xxxx-xxxx-218ae63a30b6",
instanceName: "Webhook demo"
}) {
solutionInstance {
id
name
enabled
created
}
}
}

The result will return the id of the Solution Instance:

{
"data": {
"createSolutionInstance": {
"solutionInstance": {
"id": "9e2e9b86-xxxx-xxxx-xxxx-72e84e266d4d",
"name": "Webhook demo",
"enabled": false,
"created": "2020-10-02T13:06:41.605Z",
"solution": {
"id": "91c0f56f-xxxx-xxxx-xxxx-184686978ea5",
"title": "Webhook demo",
"description": ""
},
"authValues": [],
"configValues": [],
"workflows": {
"edges": [
{
"node": {
"id": "e79e7a66-xxxx-xxxx-xxxx-16b67f870718",
"sourceWorkflowId": "804c5f50-9e7d-4b50-858b-9338c507ff45",
"sourceWorkflowName": "Webhook demo",
"triggerUrl": "https://0ed9f5b2-xxxx-xxxx-xxxx-44ab9507e4ae.trayapp.io"
}
}
]
},
"solutionVersionFlags": {
"hasNewerVersion": false,
"requiresUserInputToUpdateVersion": false,
"requiresSystemInputToUpdateVersion": false
}
}
}
}
}
At this stage, there are no authValues or configValues. They will be populated when the End User runs the Config Wizard

Create a Config Wizard authorization code

You will need to use generateAuthorizationCode (master token) to get the one-time Config Wizard code for the End User.

mutation {
generateAuthorizationCode(input: {userId: "fbb96559-xxxx-xxxx-xxxx-5552c2d2fca4"}) {
authorizationCode
clientMutationId
}
}

This will return a one-time use code which can be used in the Config Wizard url:

{
"data": {
"generateAuthorizationCode": {
"authorizationCode": "b8aab26cxxxxxxxxxxxxxxxxxxxx776c7bba7977",
"clientMutationId": null
}
}
}

Compose the Config Wizard URL

Now you can compose the url using the returned solutionInstanceId and authorizationCode from the calls above:

https://embedded.tray.io/external/solutions/${embeddedId}/configure/${solutionInstanceId}?code=${authorizationCode}

Remember that embeddedId is the value that you set when configuring your Config Wizard CSS

You can remove the tray.io domain and whitelabel the Config Wizard url. If you have done so then embedded.tray.io will be replaced with e.g. acme.integration-configuration.com

Note that the authorization code is one-time use (it will also expire if not used within a certain timeframe) and so if you make a mistake with the url and get a 401 you will need to generate a new one.

When you enter the url in your browser, you should then be presented with the Config Wizard:

As you can see you are then able to enter the auth and Config Data for the End User.

Note also that the End User is presented with the public url for their workflow instance. This can be hidden from the End User in the Solution Editor, and you can retrieve it as the triggerUrl when creating or querying the Solution Instance:

Since you have activated the pop-up directly via a URL, and not as a pop-up in your application, the Config Wizard will hang when you click 'Finish' on the final screen.

Enable the Solution Instance

You can now return to the Users section of the UI and see that the Solution Instance for that End User is there, but currently disabled (this is to allow you to make any checks or changes before an Instance is activated):

So the final step in creating a Solution Instance for an End User is that the status must be set to enabled with updateSolutionInstance (user token):

mutation {
updateSolutionInstance(input: {solutionInstanceId: "9e2e9b86-xxxx-xxxx-xxxx-72e84e266d4d",
instanceName: "Webhook demo", enabled: true
}) {
solutionInstance {
id
name
enabled
created
}
}
}

The returned data will confirm that the Solution Instance is enabled:

{
"data": {
"updateSolutionInstance": {
"solutionInstance": {
"id": "9e2e9b86-xxxx-xxxx-xxxx-72e84e266d4d",
"name": "Webhook demo",
"enabled": true,
"created": "2020-10-02T13:06:41.605Z",
"authValues": [
{
"externalId": "external_slack_authentication",
"authId": "45ec3104-xxxx-xxxx-xxxx-25e810c0c0e8"
}
],
"configValues": [
{
"externalId": "external_slack-channel",
"value": "\"CHxxxx65P\""
},
{
"externalId": "external_slack-message",
"value": "\"Hi your solution instance has worked!\""
}
],
"workflows": {
"edges": [
{
"node": {
"id": "e79e7a66-xxxx-xxxx-xxxx-16b67f870718",
"sourceWorkflowName": "Webhook demo",
"sourceWorkflowId": "804c5f50-xxxx-xxxx-xxxx-9338c507ff45",
"triggerUrl": "https://0ed9f5b2-xxxx-xxxx-xxxx-44ab9507e4ae.trayapp.io"
}
}
]
}
}
}
}
}

Trigger a run of the Workflow Instance

Now you can paste the triggerUrl into your browser address bar and hit 'enter' to trigger a run of the Workflow Instance.

Debugging the Solution Instance

Returning to the UI you will now see that the Solution Instance is enabled and you can click to debug the End User's Workflow Instance:

This will open a read-only version of the Worklow Instance:

As you can see the log data is relevant to this particular End User - reflecting the Slack Channel and message entered in the Config Wizard.

And the webhook-triggered message has been sent to the Slack channel chosen by the End User in the Config Wizard:

Please see our documentation on troubleshooting for more on debugging, log streaming and error handling.

List an End User's Solution Instances

You can pass the userId when using the solutionInstances query (user/master token) (if using the master token for this query it is still possible to filter Solution Instances by the owner of the Solution Instance, or by the ID of the Solution which it came from):

query {
viewer {
solutionInstances(criteria: { owner: fbb96559-xxxx-xxxx-xxxx-5552c2d2fca4 }) {
edges {
node {
id
name
enabled
owner
created
solutionVersionFlags {
hasNewerVersion
requiresUserInputToUpdateVersion
requiresSystemInputToUpdateVersion
}
workflows {
edges {
node {
triggerUrl
id
sourceWorkflowId
}
}
}
authValues {
externalId
authId
}
configValues {
externalId
value
}
}
cursor
}
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
}

Updating Solution Instances

When new versions of your Solutions are published, if they contain breaking changes (i.e. require new auth and / or config data), your End Users' Instances will need updated as per Updating Solutions and Instances