Journeys API Integrations
HTTP calls within Journeys
Journeys can integrate with APIs exposed over HTTP.
The functions get
, post
, put
and patch
do HTTP calls. HTTP calls allow for the following parameters:
card GetCard, then: PostCard do
get_response = get("https://example.org/endpoint",
timeout: 5_000,
cache_ttl: 60_000,
query: [
["name", "@contact.name"],
["whatsapp_id", "@contact.whatsapp_id"]
])
log("@get_response")
end
card PostCard, then: PutCard do
post_response = post("https://example.org/endpoint",
timeout: 5_000,
cache_ttl: 60_000,
body: """
{"username": @contact.whatsapp_id}
""",
headers: [["content-type", "application/json"]]
)
log("@post_response")
end
card PutCard, then: PatchCard do
put_response = put("https://example.org/endpoint",
timeout: 5_000,
cache_ttl: 60_000,
body: """
{"username": @contact.whatsapp_id}
""",
headers: [["content-type", "application/json"]]
)
log("@put_response")
end
card PatchCard do
patch_response = patch("https://example.org/endpoint",
timeout: 5_000,
cache_ttl: 60_000,
body: """
{"username": @contact.whatsapp_id}
""",
headers: [["content-type", "application/json"]]
)
log("@patch_response")
end
option | use |
---|---|
body | The body of the HTTP request |
cache_ttl | How long to cache a response for, in milliseconds (60_000 or 60000 is 60 seconds) |
headers | A list of lists with HTTP headers, [["X-Foo", "Bar"]] would add the X-Foo header to the HTTP request. |
mode | "sync" or "async" |
query | A list of lists with keys & values to use as query parameters [[key, value]] adds ?key=value to the request |
timeout | How long a request is allowed to take, in milliseconds (5_000 or 5000 is 5 seconds). A value higher than 20 seconds will be set to 20 seconds. |
url | The HTTP endpoint |
The HTTP headers and query parameters can be expressions that are evaluated.
The HTTP headers you specify will be included in addition to the following standard HTTP headers:
User-Agent: Turn/X.X.X (Journeys Webhook)
X-Turn-Journey-UUID: <the-uuid-of-the-journey>
X-Turn-Journey-Session-UUID: <the-uuid-of-the-session>
X-Turn-Journey-Environment: "staging" if the Contact is a staging user, "production" otherwise
Please note that Turn places a strict ceiling on how long it will wait for external services to respond to requests.
If your outbound call takes longer than 20 seconds to respond, the webhook call will respond with a timeout error,
even if your timeout
value is greater than 20 seconds.
We advise that you ensure any external services are performant (a less than 10 second respones time is preferred),
in order to work within these limits and ensure that the end-user on WhatsApp is not left waiting for lengthy
periods of time.
HTTP Connection Errors
If the remote side of your HTTP call times out or drops the connection,
the status of the response will be set to null
and the body
attribute of the response will have the error that occurred.
It is the journey author's responsibility to make sure connection errors and timeouts are handled gracefully in order to ensure a good user experience.
Here's an example of handling a connection error:
card Webhook, then: Report do
resp =
post("https://example.org",
body: "hello world!",
timeout: 5_000,
query: [["foo", "bar"]],
headers: [
["content-type", "text/plain; charset=utf-8"]
]
)
end
card Report when not resp.status do
text("""
Apologies, it looks like we are having some connection errors.
The response error was ```@resp.body```
Please try again later!
""")
end
card Report do
text("success")
end
RSS feed integration
Here is an example that reads the RSS feed for the BBC's Global News Podcast and allows users to navigate through the episodes and listen to them.
card Init, "⏮ Latest episode", then: Start do
# Initialize the cursor with a value of zero, this means we always start
# with the first, most recent, entry from the RSS feed
cursor = 0
# Use the public API at rss2json.com to convert the RSS feed that the
# BBC publishes for their world service podcast to a JSON file that
# we can read.
webhook =
get(
"https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fpodcasts.files.bbci.co.uk%2Fp02nq0gn.rss"
)
items = webhook.body.items
# Keep track of the total number of items
total_items = count(items)
end
card Start do
# Read the current item
item = items[cursor]
# send the audio file first, since this is a _big_ file it takes longer to arrive
# on the phone than the messages we send later.
audio("@item.enclosure.link")
# generate the buttons
buttons([Init, NextCard]) do
# send the title as a caption
text("""
*@item.title*
@item.content
_Episode @(cursor + 1) of @(total_items)_
_Published at @(item.pubDate)_
""")
# The feed unfortunately doesn't have images and so we're just using a static
# image from the BBC website
image("https://ichef.bbci.co.uk/images/ic/480x270/p09kz0v5.jpg")
end
end
# We change the text on the button depending on whether or not we have any further
# episodes. If we do we display "Next episode ➡️", if we don't we display "⏮ First episode"
#
# Also if we reach the end of the total number of episodes, we reset the counter to 0
# which has us starting at the beginning again.
card NextCard, "@IF(cursor + 1 < total_items, \"Next episode ➡️\", \"⏮ First episode\")",
then: Start do
cursor = if cursor + 1 < total_items, do: cursor + 1, else: 0
end