Till
Last updated May 01, 2017
Table of Contents
Use the Till add-on to ask questions via SMS and receive validated responses via webhook, enabling instant alerts, flash surveys, and real-time two-way communication with a simple HTTP API.
Learn more about the Till platform.
Provisioning the Till add-on
Renders vs. Messages - Control your Budget
One key Till objective is to help your business users control their budgets. We do this by charging only for “Renders”.
- A “render” is content that is converted into a message and sent
- There is no charge for inbound communication i.e. responses to questions
- The benefit to this approach is that the budget for any project is constrained by the number of renders created regardless of the response rate.
Note: Invalid responses to questions can incur extra renders as it may require asking questions multiple times. Clear, simple questions that users can easily respond to will produce better results with more efficient spend.
A list of all plans available can be found here.
Provisioning
Till can be attached to a Heroku application via the CLI:
$ heroku addons:create till
-----> Adding till to sharp-mountain-4005... done, v18 (free)
Once till
has been added a TILL_URL
setting will be available in the app configuration and will contain the canonical URL used to access your till account. This can be confirmed using the heroku config:get
command.
$ heroku config:get TILL_URL
https://platform.tillmobile.com/rpc/send/4083h0384hw0dnsvslkdnv304n30434/
After installing till
your application should be configured to fully integrate with the add-on.
Using with Python / Django or Node.js
Check out the example app in Python, or deploy it:
Check out the example app in Node.js, or deploy it:
For Python
We recommend using the requests
library when accessing the Till HTTP API.
$ pip install requests
For Node.js
we recommend using the request-json
library when accessing the Till HTTP API.
$ npm install request-json --save
Ask your first question over SMS with Till
Ask one or more users
via passed phone numbers a set of questions over SMS. Have the valid responses sent to a web hook.
Python
import os, requests
TILL_URL = os.environ.get("TILL_URL")
requests.post(TILL_URL, json={
"phone": ["15558675309", "15558675308"],
"questions" : [{
"text": "Favorite color?",
"tag": "favorite_color",
"responses": ["Red", "Green", "Yellow"],
"webhook": "https://yourapp.herokuapp.com/results/"
}],
"conclusion": "Thank you for your time"
})
Node.js
var request = require("request-json");
var url = require("url");
var TILL_URL = url.parse(process.env.TILL_URL);
var TILL_BASE = TILL_URL.protocol + "//" + TILL_URL.host;
var TILL_PATH = TILL_URL.pathname;
if(TILL_URL.query != null) {
TILL_PATH += "?"+TILL_URL.query;
}
request.createClient(TILL_BASE).post(TILL_PATH, {
"phone": ["15558675309", "15558675308"],
"questions": [{
"text": "Favorite color?",
"tag": "favorite_color",
"responses": ["Red", "Green", "Yellow"],
"webhook": "https://yourapp.herokuapp.com/results/"
}],
"conclusion": "Thank you for your time"
}, function(err, res, body) {
return console.log(res.statusCode);
});
Sending the POST
request will result in a launch
to be created in Till. The POST
will return JSON containing a project_launch_guid
to identify the launch
and corresponding URLs for tracking results and stats via the Till API:
Send API Response
{
"project_launch_guid": "ed45h45hf60f0-46bb-468a-b80a-14ad95138e83",
"stats_url": "https://platform.tillmobile.com/api/stats/ed45h45hf60f0-46bb-468a-b80a-14ad95138e83?username=45g4545g&api_key=dfdfgdg",
"results_url": "https://platform.tillmobile.com/api/results?username=343434&api_key=erergergerg&project_launch_guid=ed45h45hf60f0-46bb-468a-b80a-14ad95138e83"
}
/api/stats/
The stats API returns statistics regarding your launch and its progress.
{
// The number of "Sessions" i.e. channels of communication open between
// your phone number and your user's phone numbers. Active sessions are
// in progress i.e. questions are being answered.
"num_active_sessions": 0,
// The number of queued sessions i.e. when multiple sets of questions are sent to
// a user's phone via the same phone number. The set(s) of questions not being answered
// will be queued waiting for the user to finish the first set of questions or for 1hr
// to pass and the session to expire. This causes the active session to complete and the
// next queued session to become active.
"num_queued_sessions": 0,
// Complete sessions occur when a user has answered all their questions or
// they had a queued session that timed the active session out.
"num_complete_sessions": 1,
// The total number of questions asked
"num_questions": 0,
// The number of renders consumed when asking the user(s) questions.
// Note: Extra renders are consumed each time an invalid response is received
// and the question must be asked an additional time
"num_renders": 1,
// The number of valid results captured from all users
"num_results": 0,
// The identifier for the launch
"project_launch_guid": "34gg34g34g-sd2sdfsdf51a-34g34g-v343v44v-34vdvsdvsv",
// When did this launch start i.e. first render occurred
"project_launch_start": "2016-11-27T11:47:17.939926"
}
/api/results/
The results API returns results in the same format as the web hook with some additional meta data. Use this API call to poll for results or retrieve results from multiple launches.
{
// Meta data
"created": "2016-11-27T11:57:14.060474",
"updated": "2016-11-27T11:57:14.060538",
"guid": "wegweg-5d42-sdf-sdfsdf-sdf",
// Launch
"project_launch_guid": "445c481f-g4g-49e5-dfgdg-b96b1a5cae0f",
// Participant
"participant_guid": "34g34g43-2c30-43f5-8f6b-34g3434g",
"participant_phone_number": "+15558675309",
// Question
"question_guid": "ergeg-2c30-34g34g34g-8f6b-dffgdfgdfg",
"question_tag": "favorite_color",
"question_text": "Favorite color?",
// Result
"result_guid": "dfbdfb-2c30-43f5-8f6b-ergerg",
"result_timestamp": "2016-11-27T11:57:14.060474",
"result_answer": "2",
"result_response": "Green"
}
SMS UX Flow
The phone attached to 15558675309
should see the SMS message:
Favorite color? Please respond [1] Red, [2] Green, [3] Yellow.
Response Validation
If valid input e.g. 1
, 2
, 3
, Red
, Green
, or Yellow
is NOT
entered then a retry message will be sent. Note: This will incur additional renders:
Invalid response.
Favorite color? Please respond [1] Red, [2] Green, [3] Yellow.
If valid input is received and all questions in the questions
array have been answered the optional conclusion
text will be rendered:
Thank you for your time
Note: questions can have an optional conclude_on
attribute. If the provided value matches the user’s input will skip all remaining questions and render the conclusion
message completing the session e.g.
"questions: [{
"text": "Continue with questions?",
"responses": ["Yes", "No"],
"conclude_on": "No"
}]
Web Hook Data Collection
Valid user responses will be sent to the webhook
defined in the request e.g. https://yourapp.herokuapp.com/results/
via application/json
POST
data in the form:
{
// Launch
"project_launch_guid": "445c481f-c19c-49e5-9e84-b96b1a5cae0f",
// Participant
"participant_guid": "585897f2-2c30-43f5-8f6b-7c243e8ac4b0",
"participant_phone_number": "+15558675309",
// Question
"question_guid": "685897f2-2c30-43f5-8f6b-7c243e8ac4b0",
"question_tag": "favorite_color",
"question_text": "Favorite color?",
// Result
"result_guid": "885897f2-2c30-43f5-8f6b-7c243e8ac4b0",
"result_timestamp": "2016-11-27T11:57:14.060474",
"result_answer": "2",
"result_response": "Green"
}
Or, send an alert
Don’t ask a question, send an alert to one or more phone numbers.
Python
import os, requests
TILL_URL = os.environ.get("TILL_URL")
requests.post(TILL_URL, json={
"phone": ["15558675309", "15558675308"],
"text" : "Hello Heroku!"
})
Node.js
var request = require("request-json");
var url = require("url");
var TILL_URL = url.parse(process.env.TILL_URL);
var TILL_BASE = TILL_URL.protocol + "//" + TILL_URL.host;
var TILL_PATH = TILL_URL.pathname;
if(TILL_URL.query != null) {
TILL_PATH += "?"+TILL_URL.query;
}
request.createClient(TILL_BASE).post(TILL_PATH, {
"phone": ["15558675309", "15558675308"],
"text": "Hello Heroku!"
}, function(err, res, body) {
return console.log(res.statusCode);
});
Phone Number Format
For both examples note the phone number format. Till will attempt to normalize phone numbers into E.164 format.
Dashboard
The Till
dashboard allows you to monitor usage (renders) and response rate for the current month and all time.
The dashboard can be accessed via the CLI:
$ heroku addons:open till
Opening till for sharp-mountain-4005
or by visiting the Heroku Dashboard and selecting the application in question. Select Till
from the Add-ons menu.
Migrating between plans
Application owners should carefully manage the migration timing to ensure proper application function during the migration process.
Use the heroku addons:upgrade
command to migrate to a new plan.
$ heroku addons:upgrade till:newplan
-----> Upgrading till:newplan to sharp-mountain-4005... done, v18 ($49/mo)
Your plan has been updated to: till:newplan
How many renders do I need?
Renders have per month maximums e.g. 5,000 for each plan. However, to help ensure the reliability of the service all renders cannot be consumed at once.
A buffer of renders is provided every month and renders accrue every second the add on is provisioned.
The current available renders are returned in the Available-Renders
header and the accrual rate is returned in the Render-Accrual-Rate
header of each send
request.
If your app goes over the limit a HTTP 429
status code will be returned.
Removing the add-on
Till
can be removed via the CLI.
This will destroy all associated data and cannot be undone!
$ heroku addons:destroy till
-----> Removing till from sharp-mountain-4005... done, v20 (free)
Support
All Till
support and runtime issues should be submitted via one of the Heroku Support channels. Any non-support related issues or product feedback is welcome at Till Support.