Technical FAQs
Offering product integrations can be one of the easiest ways to expand the feature set of a product without adding loads of time and cost on development resources. Docubee currently has external integrations with Salesforce, Sharepoint, and Brother scanners that we offer to our customers. Internally, we have an integration with Slack that allows our development team to be notified of different events that happen within Docubee. As a team of engineers, we are always looking for new ways that we could possibly use Docubee with other products, and luckily, we usually find some time to prototype out these integrations.
Being an Apple enthusiast myself, one of the first things I wanted to try to integrate Docubee with was Apple HomeKit so I could use Siri to launch workflows. I configured my Apple TV to work with the Home app and was all ready to go. Unfortunately, I quickly found out that HomeKit does not natively support customizations like this. Lucky for me, someone had already come up with a solution to this problem using Homebridge and a node module called homebridge-cmdswitch2.
According to their Github, Homebridge is “a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API” and homebridge-cmdswitch2 “allows you to run Command Line Interface (CLI) commands via HomeKit”. After that, the setup was pretty simple to get everything working. I had to create a workflow in Docubee that I wanted to start, configure my Home app to work with Homebridge, and write this config file below. Before I knew it, Siri was launching workflows for me.
{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"pin": "031-45-154"
},
"description": "Homebridge Docubee Config",
"accessories": [],
"platforms": [{
"platform": "cmdSwitch2",
"name": "CMD Switch",
"switches": [{
"name" : "Docubee Workflow",
"on_cmd": "curl -d '{\"wfModelId\":\"ec6e7fc4-1c38-4ebf-8a32-a02ba6721ffe\", \"wfData\": {}}' -H \"Content-Type: application/json\" -X POST {LAUNCH_WORKFLOW_ENDPOINT}",
"state_cmd": "exit 1",
"off_cmd": "echo off"
}]
}]
}
One of the next integrations I wanted to try to play with was Slack. I mentioned that we already use it internally, but I wanted to see if there was a way that we could make a Slack integration that was useful for an end-user. After creating my own Slack app to play with, I wanted to be able to launch a workflow from Slack as well as send a message back to Slack notifying me that a workflow was launched. To do both of these things, I had to create a handler somewhere to take the callback IDs that Slack would send to our API and do something with them. The finished handler looked like this:
'use strict';
const qs = require('qs');
const request = require('request')
function handleInteractiveMessage(req, res) {
const task = req.task;
res.status(200);
res.end();
task.log.info({ source: 'slack-connector.handInteractiveMessage' }, qs.parse(req.body));
const payload = JSON.parse(qs.parse(req.body).payload);
const responseUrl = payload.response_url;
const callbackId = payload.callback_id;
task.log.info({ source: 'slack-connector.handleInteractiveMessage', responseUrl }, 'response url');
task.log.info({ source: 'slack-connector.handleInteractiveMessage', callbackId }, 'callback id');
if (payload.callback_id === 'docubee_workflow_start') {
kickOffWorkflow(task);
} else if (payload.callback_id === 'handle_workflow_actions' && payload.actions[0].value !== 'redirect') {
confirmCancelWorkflow(task, responseUrl, payload.actions[0].value);
} else if (payload.callback_id === 'confirm_cancel_workflow' && payload.actions[0].value !== 'No') {
cancelWorkflow(task, payload.actions[0].value, responseUrl)
}
}
function confirmCancelWorkflow(task, responseUrl, wfInstanceId) {
return new Promise((resolve, reject) => {
task.log.info({ source: 'slack-connector.confirmCancelWorkflow', wfInstanceId }, 'wf instance id');
request({
url: responseUrl,
method: 'POST',
json: true,
body: {
text: 'Are you sure you want to cancel this workflow?',
attachments: [
{
fallback: 'See what\'s going on!',
author_name: 'Owner: ntorretti',
title: 'Confirm Cancel',
text: 'Please confirm you want to cancel this workflow',
callback_id: 'confirm_cancel_workflow',
actions: [
{
name: 'action',
type: 'button',
text: 'Yes',
style: '',
value: wfInstanceId
},
{
name: 'action',
type: 'button',
style: '',
text: 'No',
value: 'No'
}
]
}
]
}
}, (err, response) => {
if (err) {
task.log.error({ source: 'slack-connector.confirmCancelWorkflow', err }, 'whoops');
reject(err);
} else {
task.log.info({ source: 'slack-connector.confirmCancelWorkflow', response }, 'response');
resolve({ status: 'Request successfully sent to callback API endpoint.' });
}
});
});
}
function sendCancelConfirmation(task, responseUrl) {
return new Promise((resolve, reject) => {
request({
url: responseUrl,
method: 'POST',
json: true,
body: {
text: 'We have successfully cancelled your workflow.',
}
}, (err, response) => {
if (err) {
task.log.error({ source: 'slack-connector.sendCancelConfirmation', err }, 'whoops');
reject(err);
} else {
task.log.info({ source: 'slack-connector.sendCancelConfirmation', response }, 'response');
resolve({ status: 'Request successfully sent to callback API endpoint.' });
}
});
});
}
function cancelWorkflow(task, wfInstanceId, responseUrl) {
return new Promise((resolve, reject) => {
request({
headers: { 'content-type': 'application/json' },
url: {CANCEL_WORKFLOW_ENDPOINT},
method: 'POST'
}, (err, response) => {
if (err) {
task.log.error({ source: 'slack-connector.cancelWorkflow', err }, 'whoops');
reject(err);
} else {
task.log.info({ source: 'slack-connector.cancelWorkflow', response }, 'yay');
sendCancelConfirmation(task, responseUrl);
resolve(response);
}
});
});
}
function kickOffWorkflow(task) {
return new Promise((resolve, reject) => {
request({
headers: { 'content-type': 'application/json' },
url: {LAUNCH_WORKFLOW_ENDPOINT},
method: 'POST',
body: JSON.stringify({
wfModelId: 'd32aa8ba-f153-46b5-8c62-81d14327c924',
wfInstanceName: 'Untitled',
wfData: {
Originator: 'Natalie Torretti',
Originator_Email: 'ntorretti@accusoft.com',
email: 'ntorretti@accusoft.com'
}
}),
}, (err, response) => {
if (err) {
task.log.error({ source: 'slack-connector.handleInteractiveMessage', err }, 'whoops');
reject(err);
} else {
task.log.info({ source: 'slack-connector.handleInteractiveMessage', response }, 'yay');
resolve(response);
}
});
});
}
module.exports.initialize = (params, imports, ready) => {
const framework = imports['prv-common-service-base'];
const task = framework.taskLogging.createTask();
const server = imports.server;
task.begin('Initializing Slack connector component');
server.post('/interactiveMessage', handleInteractiveMessage);
task.log.info({ source: 'slack-connector.initialize' }, 'Slack connector component initialized');
task.end();
ready();
};
Slack has some great documentation and really is built to handle these kind of integrations. It was not that much work to get everything configured after I had the connector in place. I still needed one more piece of code on the Docubee end to be able to actually send the message to Slack. That send message function ended up looking like this:
const sendSlackMessage = imports => (task, redirectUrl, workflowInstanceId, message) => {
return new Promise((resolve, reject) => {
task.log.info({ source: 'utils.sendSlackMessage' }, 'sending slack message');
request({
url: 'https://hooks.slack.com/services/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',
method: 'POST',
json: true,
body: {
text: JSON.stringify(message),
attachments: [
{
fallback: 'See what\'s going on!',
author_name: 'Owner: ntorretti',
title: 'Workflow Actions',
text: 'Here are some actions you can take!',
callback_id: 'handle_workflow_actions',
actions: [
{
name: 'action',
type: 'button',
text: 'View dashboard',
style: '',
value: 'redirect',
url: {LINK_URL}
},
{
name: 'action',
type: 'button',
text: 'Go to workflow',
style: '',
value: 'redirect',
url: redirectUrl
},
{
name: 'action',
type: 'button',
style: '',
text: 'Cancel Workflow',
value: workflowInstanceId
}
]
}
]
}
}, (err, response) => {
if (err) {
task.log.error({ source: 'utils.sendSlackMessage', err }, 'whoops');
reject(err);
} else {
task.log.info({ source: 'utils.sendSlackMessage', response }, 'response');
resolve({ status: 'Request successfully sent to callback API endpoint.' });
}
});
});
}
We called this the send SlackMessage function after the “Start Demo Workflow” was started. This sends a message back to Slack that gives the user a couple different actions that they could take on that message. If a user clicked one of the buttons in the message, a request with a specific callback ID was sent to the slack handler and the appropriate action was taken. The first image below shows how I integrated starting a workflow in Slack and the second image shows the message we sent back to Slack after a workflow was started giving the user different actions they can take.
These are just a few ways that Accusoft’s Docubee can be integrated into your daily routines. Whether it’s starting a workflow with Siri or enabling automated Slack processes, Docubee is built to help you and your organization to find the best way to automate processes.
Natalie Torretti, Software Engineer III
Natalie joined Accusoft as a software engineer in 2016. She started on the eDocr team but has spent the last two and a half years on Docubee development team. Natalie has been a large contributor to the React front-end UI of Docubee and made several enhancements to the back-end microservices as well. She obtained her B.S. in Biobehavioral Health with a Psychology minor from Penn State as well as her A.S.T. in Information Technology from South Hills School of Business and Technology. When Natalie is not writing code she enjoys working out, spending time at the pool, and playing with her dogs.
Docubee is a great no-code platform for automating your business processes. If you are a developer, we offer several ways to integrate Docubee directly into your site with straightforward APIs, and a few lines of code. If that isn’t your speed, no worries! You can learn more about how you can use Docubee code free here. Otherwise, read on!
You’ve got your perfect website and your customers know and love your unique style. With Docubee, it’s easy to use your own forms to collect data and much more. With additional effort, you could even send documents hosted on your site to Docubee and auto-populate them with data collected in a form.
To demonstrate a very simple use-case, here is a survey form in Docubee which can be used to collect and track response data. The Docubee workflow will be a very simple two step process – a web form and email step. Check out how to create a workflow template here.
The Docubee Workflow
Using Docubee’s fast form creator, it was easy to create a simple survey form.
Once created and published, the workflow’s form can be directly linked via URL for collecting survey data, or it can be submitted from your own site by initiating a POST request. This way you don’t need to worry about storing the data. Docubee allows you to track and export all responses.
Each field in the workflow designer has a Field Label and Property Name. The label is what shows up on the Docubee web form, and the Property Name is what the response data corresponds with in the Docubee dashboard.
So far, there are six “Single-Line Text” fields on the form, five of which have a data type of text and one of type e-mail.
(Label / Property Name)
- What is your favorite product? / Favorite_Product
- Why did your purchase this product? / Why_Purchase_Product
- How satisfied are you with this product? / Product_Satisfaction
- Would you recommend this product to a friend? / Recommend_Product
- Would you recommend this company to a friend? / Recommend_Company
- Your Email / Respondent_Email
The property name is also how the data is stored in the POST request body to Docubee that initiates the workflow.
The Docubee API
The workflow can be initiated from your site by having your form post to custom route on your server. The handler behind that route needs to format your forms response data to POST to the workflow instances API endpoint:
POST - https://docubee.app/api/v1/workflowInstances
Content-Type: application/json
Request Body
{
"wfModelId": "yourModelIdHere",
"wfData": {
"Favorite_Product": "yourDataHere",
"Why_Purchase_Product": "yourDataHere",
"Product_Satisfaction": "yourDataHere",
"Recommend_Product": "yourDataHere",
"Recommend_Company": "yourDataHere",
"Respondent_Email": "yourDataHere"
}
}
Response
Content-Type: application/json
{
"wfInstanceId": "instance-id",
"redirectUrl": "url-if-there-is-a-next-workflow-step"
}
After a successful POST request, the workflow will be initiated with the data and a thank you email would be automatically sent to the email contained in the “Respondent_Email” property.
The survey responses can be tracked in the Docubee Dashboard under the “COMPLETED” instances tab.
All survey results can also be exported to a CSV file using the “Export Workflows” button.
Example CSV Export:
Docubee can be used for a wide variety of different use cases, from something as simple as collecting survey data, to more advanced use-cases requiring documents hosted on your site to be automatically populated with data.
Reach out today to schedule a demo, or to get started integrating Docubee’s other powerful APIs into your product. For more advanced use-cases our Professional Services team would be more than happy to assist.
Check out more here.
Landon Lamb, Software Engineer III – Docubee Team
Landon started out as a Software Engineer in Support at Accusoft in July 2016. In April of 2017, he transitioned onto the Docubee team initially as a Workflow Developer.
Currently, Landon is a Software Engineer III and works on the front end site, the back end services, and the product’s build pipeline. He enjoys helping deliver new features to Docubee’s growing user base.