<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniele</title>
    <description>The latest articles on Forem by Daniele (@i_am_daniele).</description>
    <link>https://forem.com/i_am_daniele</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F149708%2Fad4b5adb-0957-418a-aee2-58a29374a773.jpg</url>
      <title>Forem: Daniele</title>
      <link>https://forem.com/i_am_daniele</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/i_am_daniele"/>
    <language>en</language>
    <item>
      <title>Build a low-code chatbot using Autohook and YAML</title>
      <dc:creator>Daniele</dc:creator>
      <pubDate>Thu, 16 Apr 2020 17:56:15 +0000</pubDate>
      <link>https://forem.com/i_am_daniele/build-a-low-code-chatbot-using-autohook-and-yaml-16p3</link>
      <guid>https://forem.com/i_am_daniele/build-a-low-code-chatbot-using-autohook-and-yaml-16p3</guid>
      <description>&lt;p&gt;Chatbots are useful to provide relevant and timely information via direct messages. Developers can build logic to create a ‘script’ that directs users to the relevant answers they’re looking for. &lt;br&gt;
I’m amazed by the people coming together in this current crisis to help however they can. I wanted to do my part and hope that it inspires others to contribute too. Chatbots can be used to help people find information from reputable sources. In my &lt;a href="https://dev.to/twitterdev/how-to-build-a-complete-twitter-autoresponder-in-less-than-100-source-lines-of-code-with-autohook-16j0"&gt;previous tutorial&lt;/a&gt;, I used &lt;a href="https://www.npmjs.com/package/twitter-autohook" rel="noopener noreferrer"&gt;Autohook&lt;/a&gt; to reply to direct messages with little code. Still, you will need to define the flow between a user and a bot, and that logic is usually tailored for each project.&lt;/p&gt;

&lt;p&gt;I wanted to build something that requires minimal coding, so that anyone could build a useful service. I created a low-code, bot framework that pulls together all the relevant bits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It uses Autohook to receive direct message events&lt;/li&gt;
&lt;li&gt;It defines a set of text files with the logic to reply to a user&lt;/li&gt;
&lt;li&gt;It configures a welcome message for an account designed as chat agent&lt;/li&gt;
&lt;li&gt;It uses the Twitter API to send a direct message to the user who contacted the chat agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this framework, I built a bot that provides regional information about COVID-19 for the US, Spain and Italy, which are severely affected by the current emergency. By chatting with the bot, you can get useful resources from local authorities, and find ways to donate. &lt;/p&gt;

&lt;p&gt;The bot uses public domain information from the CDC, Italy’s Ministero della Salute (Ministry of Health) and the Spanish Ministerio de Sanidad, Consumo y Bienestar Social (Ministry of Health, Consumer Affairs and Welfare). The bot needs to adapt to the situation in each country; for example, people in Italy need a certificate to travel, and the bot should be able to provide the link to the official website to fill the form to Italian users.&lt;/p&gt;

&lt;p&gt;The project is also configured to run either locally or on a remote server. You can find the full project on &lt;a href="https://glitch.com/edit/#!/remix/covid-helper-bot" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;, and you can &lt;a href="https://t.co/qIL5ihKvmx" rel="noopener noreferrer"&gt;interact with the final result&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup your Twitter app
&lt;/h2&gt;

&lt;p&gt;To get started, you need to set up a Twitter app and to have a valid developer account. We covered this process in my &lt;a href="https://dev.to/twitterdev/how-to-build-a-complete-twitter-autoresponder-in-less-than-100-source-lines-of-code-with-autohook-16j0"&gt;previous tutorial about Autohook&lt;/a&gt;. Read the section named “Your Twitter app” to learn more.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building our flow
&lt;/h2&gt;

&lt;p&gt;There seems to be no in-between when it comes to setting up the actual conversation flow. Developers either build custom logic with code, or they purchase access to sophisticated interactive workflow automation platforms. On Twitter, chatbots are equipped with &lt;a href="https://business.twitter.com/en/help/campaign-editing-and-optimization/quick-replies.html" rel="noopener noreferrer"&gt;quick reply options&lt;/a&gt;, so we can build a flow based entirely on the inputs from these quick replies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dwdkxlbzoljheujlk07.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dwdkxlbzoljheujlk07.PNG" alt="Screenshot of a Twitter direct message with a chat bot. In this screenshot, the chatbot is using a multi-language welcome message to greet a Twitter user the first time they start a conversation. Three quick reply options (one per language) are also shown."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By relying on quick replies, we can turn our chatbot into a finite-state machine; in other words our bot can be in exactly one state at any given time, and the number of states are predetermined (finite). This seems to be exactly what we need!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each reply from the chatbot will have one or more quick reply option&lt;/li&gt;
&lt;li&gt;The user can only tap one option per reply&lt;/li&gt;
&lt;li&gt;Each option brings the bot to the next state&lt;/li&gt;
&lt;li&gt;The state is basically our next message&lt;/li&gt;
&lt;li&gt;Any user input from the keyboard is discarded; it will simply trigger a “do not understand” reply, and it will repeat the last message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I mentioned my bot is answering in three languages. How do we apply the finite-state paradigm to our flow? In this case, each language is a state, plus another state for the “do not understand” case (more about that later). Users can only select one option (a language in this case); any other input triggers a “do not understand” message, bringing the user back to the language selector.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nn0rwnmfis3w9mhpqm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nn0rwnmfis3w9mhpqm2.png" alt="A diagram of a finite-state machine. The starting point is the welcome message, and each subsequent state is driven by a quick reply option. Because the number of option is finite, each option will drive to one state."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the diagram, each bubble represents a chat message from our bot, and each arrow is an input from the user. By giving our bot a finite-state mindset, we can be sure to articulate the full conversation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write, don't code
&lt;/h2&gt;

&lt;p&gt;How do we translate that conversation into code? We don’t. Instead of writing code, we will write text files. Each file will contain one or more bubbles as defined in our diagram. Each bubble will list the options it supports. Each option will bring the user to the next state.&lt;br&gt;
We will use the YAML format for our text files; this way we can specify tags and lists of options – which is exactly what we need to build our quick replies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;🇺🇸 Hi! I'm a bot and I'll help you with resources on COVID-19. Please select your country.&lt;/span&gt;

    &lt;span class="s"&gt;🇮🇹 Ciao! Sono un robot e posso aiutarti con risorse utili su COVID-19. Per favore, seleziona la tua nazione.&lt;/span&gt;

    &lt;span class="s"&gt;🇪🇸 ¡Hola! Soy un robot y puedo ayudar con recursos utiles sobre la COVID-19. Por favor, selecciona tu nación.&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🇺🇸 United States&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Contains resources from CDC&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scripts/en-us/for-me.yaml#start&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🇮🇹 Italia&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Usa le linee guida del Ministero della Salute&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scripts/it-it/for-me.yaml#start'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🇪🇸 España&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Con las lineas guias del MSCBS&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scripts/es-es/for-me.yaml#start'&lt;/span&gt;
&lt;span class="na"&gt;do_not_understand&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;🇺🇸 I'm sorry, I can't read what you type. Please try again by selecting one of the options instead of using your keyboard.&lt;/span&gt;

    &lt;span class="s"&gt;🇮🇹 Mi dispiace, non posso leggere quello che scrivi. Per favore, prova di nuovo selezionando una delle opzioni anziché usare la tastiera.&lt;/span&gt;

    &lt;span class="s"&gt;🇪🇸 Lo siento, no puedo leer lo que escribes. Por favor, intenta seleccionar una de las opciones en vez de escribir.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then pass these files to our finite-state machine processor. The Agent module simply opens the file specified in the metadata field, gets the bubble with the name specified after the &lt;code&gt;#&lt;/code&gt; character, and handles that over to the code that will send the direct message back to the user.&lt;/p&gt;

&lt;p&gt;In practical terms, our language selector contains three options. When the user selects España, our finite-state machine will open the file &lt;code&gt;scripts/es-es/for-me.yaml&lt;/code&gt; and look for a bubble named &lt;code&gt;start&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;EventEmitter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;loadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Exception:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;currentStep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`No entry point named &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; defined in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Add the entry point in your script file.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;step&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send the message
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;twitter_dm.js&lt;/code&gt; module contains the logic to send direct messages; here we’re simply wrapping the send logic from my previous tutorial in a separate module to keep things tidy.&lt;br&gt;
The JSON payload for a direct message is quite verbose, so we added a &lt;code&gt;MessageCreate&lt;/code&gt; class. It helps compose the JSON body easily, and it will also translate incoming JSON requests into a valid message. This can allow us to translate raw JSON directly into a chat bubble with no effort!&lt;/p&gt;

&lt;h2&gt;
  
  
  I don’t understand – is it really that easy?
&lt;/h2&gt;

&lt;p&gt;The only thing left to handle is keyboard input. The chatbot will simply acknowledge its ignorance – it will send a message saying it doesn’t understand, then it will send the previous message again. How do we handle this case?&lt;/p&gt;

&lt;p&gt;Our finite-state machine will once again help us. After all, we defined any other input to be just one case, so we will need to define that “do not understand” case as a bubble too. Because the keyboard input will not send metadata, we will have our agent fall back to that “do not understand” bubble when our code does not receive metadata. We then call our previous agent’s step again to display the options.&lt;/p&gt;

&lt;p&gt;In the code, you can see how we're even localizing the message if the user has already selected a language!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnp95xg3r4k7zzqjqacsh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnp95xg3r4k7zzqjqacsh.jpeg" alt="In this screenshot, I typed something in my chat window. The chatbot is not built to understand things users will type, so it will reply with a generic message saying it doesn't understand."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We hope that you will dig in and take the code for a spin! As I mentioned, if you’d like to add other languages or enhance it further, you can find the full project on &lt;a href="https://github.com/twitterdev/covid19-helper" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. If you add anything, submit a pull request! If you want to try it live you can &lt;a href="https://t.co/qIL5ihKvmx" rel="noopener noreferrer"&gt;interact with the final result&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used several libraries and services beyond the Twitter API to make this tutorial, but you may have different needs and requirements and should evaluate whether those tools are right for you. Let me know if this inspires you to build anything!&lt;/p&gt;

</description>
      <category>twitter</category>
      <category>api</category>
      <category>chatbot</category>
      <category>covid</category>
    </item>
    <item>
      <title>Hey Siri, text my latest Tweet</title>
      <dc:creator>Daniele</dc:creator>
      <pubDate>Thu, 21 Nov 2019 17:06:45 +0000</pubDate>
      <link>https://forem.com/twitterdev/hey-siri-text-my-latest-tweet-1h4l</link>
      <guid>https://forem.com/twitterdev/hey-siri-text-my-latest-tweet-1h4l</guid>
      <description>&lt;p&gt;As someone whose first language isn’t English, I tend to find myself Tweeting and dreaming in English; many of my friends do not. And I'm too lazy to translate my Tweets.&lt;/p&gt;

&lt;p&gt;I also happen to like iOS 13 a lot. Dark Mode looks fantastic, and I'm enjoying Memojis a little too much. But my favorite app has to be Shortcuts. It ships by default with iOS 13, and it's more powerful than ever. With Shortcuts, you can instruct Siri to do things for you, including tasks no other app can do.&lt;/p&gt;

&lt;p&gt;Shortcuts is a true hidden gem; its power and ease of use allows you to build automations without writing a single line of code. The app is extremely powerful; among other things, it has a HTTP client and a JSON parser. This is all you need to connect to any API.&lt;br&gt;
So I thought, what if I can translate my latest Tweet, and send it only to my friends? Shortcuts can translate for me, and I can use Twitter Developer Labs to get my Tweets. Labs is our program where we’re building our next API in the open by inviting developers to help shape the future of the Twitter API. You can test drive new features and even full endpoints before they are broadly released, and you can tell us what you like and we can improve through our feedback channel (we already shipped some features based on feedback from people like you). It's free and you can try it out now.&lt;br&gt;
Here's what we're going to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get access to Labs&lt;/li&gt;
&lt;li&gt;Tell Shortcuts to generate a bearer token&lt;/li&gt;
&lt;li&gt;Get our latest Tweet using Labs&lt;/li&gt;
&lt;li&gt;Ask Shortcuts to translate the Tweet&lt;/li&gt;
&lt;li&gt;Send an iMessage with the Tweet&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  🧪 Enter Labs
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;If you already activated &lt;strong&gt;&lt;em&gt;Tweets and users&lt;/em&gt;&lt;/strong&gt; you can jump to the next section.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For this tutorial, you need access to Labs and the API. First though, you will need a valid app – if you don't have one, you can apply on our &lt;a href="https://developer.twitter.com" rel="noopener noreferrer"&gt;Developer site&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Once you have an app, &lt;a href="https://developer.twitter.com/en/account/labs" rel="noopener noreferrer"&gt;join Labs&lt;/a&gt; and follow the instructions (it only takes a minute). When done, you should see a list of endpoints:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9y2rilvjc4tfdimnwixt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9y2rilvjc4tfdimnwixt.png" alt="A list of endpoints. Under "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, you're going to deal with &lt;strong&gt;Tweets and users&lt;/strong&gt;, so select &lt;strong&gt;Activate&lt;/strong&gt; for that row, and attach the app you want to enable (you can enable one app per endpoint, but multiple endpoints can be attached to the same app).&lt;br&gt;
Now, go to your &lt;a href="https://apps.twitter.com/" rel="noopener noreferrer"&gt;app list&lt;/a&gt;, locate the app you've just enabled for Tweets and users, and take note of the consumer key and secret.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🤖 Coding with no code
&lt;/h1&gt;

&lt;p&gt;Now we'll start coding… With no code. Shortcuts allows you to assemble tasks together, and if you know how to use an API, it's even more flexible.&lt;/p&gt;

&lt;p&gt;Open the Shortcuts app (if you don't have it, you can download it for free from the App Store). Tap &lt;strong&gt;Create Shortcut&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the first screen, tap &lt;strong&gt;Add Action&lt;/strong&gt;. You'll see a lot of options, but you simply need a place to store your configuration (your credentials and your Twitter username). To do so, you're going to use a dictionary:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmh7fbloyq601jr86f5z2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmh7fbloyq601jr86f5z2.gif" alt="This animation shows how to tap Add action, and type Dictionary to select a Dictionary."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure the dictionary with three keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;consumer key&lt;/code&gt; with your consumer key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;consumer secret&lt;/code&gt; with your consumer secret&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;username&lt;/code&gt; with your Twitter username (without &lt;code&gt;@&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkau4z9v2b6p7z5y4prjs.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkau4z9v2b6p7z5y4prjs.jpeg" alt="My dictionary filled with three keys and values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's request a Bearer token. To do so, we need to call the Twitter API by combining your consumer key and secret with a colon, for example, &lt;code&gt;consumer key:consumer secret&lt;/code&gt;, then encode in base64, and send the resulting string in the &lt;code&gt;Authorization&lt;/code&gt; header. In Shortcuts, we simply have to add a text component to combine the credentials, then add a Base64 Encode step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj4mp88u126x47mvnuk5o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj4mp88u126x47mvnuk5o.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, create your actual request. Like I said, Shortcuts contains a full HTTP client, so for this step you just have to fill in the blanks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Get contents of URL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;https://api.twitter.com/oauth2/token&lt;/code&gt; as the URL.&lt;/li&gt;
&lt;li&gt;Tap &lt;strong&gt;Show more&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Method&lt;/strong&gt;, select POST.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Headers&lt;/strong&gt;, add Basic, then select &lt;strong&gt;⚙️ Base64 Encoded&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Request Body&lt;/strong&gt;, select &lt;strong&gt;Form&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add a field called &lt;code&gt;grant_type&lt;/code&gt;. Its value should be &lt;code&gt;client_credentials&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbtnchviuakj06y55ddem.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbtnchviuakj06y55ddem.jpeg" alt="This steps should have the Authorization header set to Basic, and the Request Body set to Form."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shortcuts has built-in JSON support. Our response will be JSON, so all we have to do is to tell Shortcut to retrieve the &lt;code&gt;access_token&lt;/code&gt; field. Just add a &lt;strong&gt;Get Dictionary Value&lt;/strong&gt; step after your request:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcp0kyogktrnkp0d1y8hj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcp0kyogktrnkp0d1y8hj.jpeg" alt="Select the Dictionary Value step and drop it as the current step."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Get your latest Tweet
&lt;/h1&gt;

&lt;p&gt;You’re now ready to get your latest Tweet, and Labs is going to help us a lot. In &lt;a href="https://developer.twitter.com/en/docs/labs/tweets-and-users?utm_source=devto" rel="noopener noreferrer"&gt;Tweets and users&lt;/a&gt;, there are two API endpoints (one to get Tweets, one to get users). In this case, you're going to use the users endpoint, because it always returns the ID of the most recent Tweet from the users you're requesting. But wait, you need the full Tweet, not just its ID! How can you avoid making another request just to get the full Tweet?&lt;/p&gt;

&lt;p&gt;Thankfully, one of my favorite Labs features is going to help you a lot here. It's called &lt;a href="https://developer.twitter.com/en/docs/labs/overview/whats-new/expansions?utm_source=devto" rel="noopener noreferrer"&gt;expansions&lt;/a&gt;, and it allows you to get a full object instead of its ID. It works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If I request &lt;code&gt;/labs/1/users?usernames=i_am_daniele&lt;/code&gt; I get my user and most recent Tweet ID back&lt;/li&gt;
&lt;li&gt;If I request &lt;code&gt;/labs/1/users?usernames=i_am_daniele&amp;amp;expansions=most_recent_tweet_id&lt;/code&gt; I get my user and my most recent Tweet back (including its text!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So now you’re going to create two steps. The first is a simple &lt;strong&gt;Get value&lt;/strong&gt; for &lt;code&gt;username&lt;/code&gt; from the dictionary you created at the very beginning. The second step is another &lt;strong&gt;Get contents of URL step&lt;/strong&gt; configured like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get contents of &lt;code&gt;https://api.twitter.com/labs/1/users?usernames=&lt;/code&gt; Dictionary value &lt;code&gt;&amp;amp;expansions=most_recent_tweet_id&lt;/code&gt; (yes, you can combine strings and variables together)&lt;/li&gt;
&lt;li&gt;Tap &lt;strong&gt;Show more&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add a Header named &lt;strong&gt;Authorization&lt;/strong&gt;. Its value should be &lt;code&gt;Bearer&lt;/code&gt; (leave a space after Bearer)&lt;/li&gt;
&lt;li&gt;Tap the magic wand icon on your keyboard, scroll back up a little, then tap on the "Dictionary value" label from "Get value for access_token in Contents of URL".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fk8ta81i07zznt2hvejfr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fk8ta81i07zznt2hvejfr.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's add these next steps to get the actual Tweet text:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ukwvpw3cec0ym4dkzjy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ukwvpw3cec0ym4dkzjy.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🇺🇸🇪🇸 Translate
&lt;/h1&gt;

&lt;p&gt;Now that you have your Tweet, you can ask Shortcuts to translate it. The app is integrated with Microsoft Translator, so all you have to do is to add the &lt;strong&gt;Translate Text with Microsoft&lt;/strong&gt; block to your workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa7tzc2wnezlglgph5ibu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa7tzc2wnezlglgph5ibu.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  💬 ¡Enviamos!
&lt;/h1&gt;

&lt;p&gt;Now it's time to send your text. First, combine the translated Tweet with a URL via a Text snippet, and then add a Send Message block. You can disable Show More -&amp;gt; Show when Run so your action runs seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1yyxzyahnyvtch3n2s4a.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1yyxzyahnyvtch3n2s4a.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have Hey Siri enabled, try saying "Hey Siri, text my latest Tweet" to always be in touch with your friends, no matter what the language of your Tweets!&lt;/p&gt;

</description>
      <category>twitter</category>
      <category>api</category>
      <category>ios</category>
      <category>twitterapi</category>
    </item>
    <item>
      <title>How to build a complete Twitter autoresponder in less than 100 source lines of code with Autohook</title>
      <dc:creator>Daniele</dc:creator>
      <pubDate>Mon, 26 Aug 2019 23:17:54 +0000</pubDate>
      <link>https://forem.com/xdevs/how-to-build-a-complete-twitter-autoresponder-in-less-than-100-source-lines-of-code-with-autohook-16j0</link>
      <guid>https://forem.com/xdevs/how-to-build-a-complete-twitter-autoresponder-in-less-than-100-source-lines-of-code-with-autohook-16j0</guid>
      <description>&lt;p&gt;&lt;em&gt;This tutorial was originally published in the &lt;a href="https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/twitter-account-activity-tutorial-autohook?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;Twitter Developer&lt;/a&gt; website&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/overview.html?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;Account Activity API&lt;/a&gt; is one of the most versatile APIs in the Twitter Developer Platform. With this API, people can allow your app to get notifications about their activity on Twitter. What’s best, it uses webhooks to deliver real time updates.&lt;/p&gt;

&lt;p&gt;Developers can achieve a lot with the Account Activity API. For example, companies can use this API to get a sense of how the global conversation is unfolding around their products and services. A popular use case is with customer service, where your favorite brands can reply to your Direct Messages in real time, and determine the best next action. This usually involves using the Account Activity API, configuring a webhook, figuring out OAuth, and understanding how to send back a message using additional Twitter APIs.&lt;/p&gt;

&lt;p&gt;This would sound like quite the task, if you didn’t have the right tools. Thankfully, &lt;a href="https://github.com/TwitterDev/autohook" rel="noopener noreferrer"&gt;Autohook&lt;/a&gt; is here to make things extremely easy for you.&lt;/p&gt;

&lt;p&gt;Autohook is a Node.js module and a command line tool that sets up webhooks for you. This way, you can spend zero time figuring out how a webhook works and instead focus on building awesome things on Twitter.&lt;/p&gt;

&lt;p&gt;Autohook makes things very easy — so easy that you can automate a DM conversation on Twitter in less than 100 lines of code. We’ll build a simple autoresponder that’ll greet whoever Direct Messages your user. Here’s what we’re going to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We’ll set up a project, including a Twitter app enabled with an Account Activity environment&lt;/li&gt;
&lt;li&gt;We’ll set up Autohook, so it will do all the hard work for us&lt;/li&gt;
&lt;li&gt;We’ll build the logic to only respond to incoming Direct Messages&lt;/li&gt;
&lt;li&gt;We’ll add a way to show messages as read&lt;/li&gt;
&lt;li&gt;We’ll show a typing indicator before sending the message&lt;/li&gt;
&lt;li&gt;We’ll send back a sample autoresponder message&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Your Twitter app
&lt;/h1&gt;

&lt;p&gt;First things first: in order to use Twitter’s Account Activity API, you will need to create an app on Twitter, and give it the &lt;strong&gt;Read, write, and Direct Messages&lt;/strong&gt; permission. You also need to have a valid development environment assigned to this app. Chances are you’ve already done this: if so, you should see something like this in your &lt;a href="https://developer.twitter.com/en/account/environments" rel="noopener noreferrer"&gt;dev environments&lt;/a&gt; page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6rd1c21vzf4xrtw9npt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6rd1c21vzf4xrtw9npt.png" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t already have a dev environment created, simply click &lt;strong&gt;Set up dev environment&lt;/strong&gt;, type a label and assign it to an app. The label can be anything, but make sure you remember it because you’re going to need it for later.&lt;/p&gt;

&lt;p&gt;You will need to get your access tokens from your &lt;a href="https://developer.twitter.com/en/apps" rel="noopener noreferrer"&gt;Twitter app dashboard&lt;/a&gt;. From the app that contains the environment you just created, click &lt;strong&gt;Details&lt;/strong&gt;, then click &lt;strong&gt;Keys and tokens&lt;/strong&gt;. Make a note of the values reported under:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API key&lt;/li&gt;
&lt;li&gt;API secret key&lt;/li&gt;
&lt;li&gt;Access token&lt;/li&gt;
&lt;li&gt;Access token secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a file in your home folder called &lt;code&gt;.env.twitter&lt;/code&gt;, and add the values you found in that page, plus your environment label:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TWITTER_CONSUMER_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Details ➡️ API key 
&lt;span class="nv"&gt;TWITTER_CONSUMER_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Details ➡️ API secret key 
&lt;span class="nv"&gt;TWITTER_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Details ➡️ Access token 
&lt;span class="nv"&gt;TWITTER_ACCESS_TOKEN_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Details ➡️ Access token secret 
&lt;span class="nv"&gt;TWITTER_WEBHOOK_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Your &lt;span class="nb"&gt;env &lt;/span&gt;label
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Developers are often confused by consumer keys and access tokens. Long story short, think of those as if they were encrypted username and passwords. A consumer key/secret pair are identify your app, while access tokens are user credentials. This means your consumer key/secret do not change, but your access token/secret changes based on the user who’s authenticating with your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jxaz04777ct00qs54qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jxaz04777ct00qs54qh.png" alt="This images shows that different users authenticate using different access tokens, while the consumer key and secret are always the same, because they belong to the authenticating app." width="624" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ve probably noticed that if you’re the owner of your own app, &lt;code&gt;TWITTER_ACCESS_TOKEN&lt;/code&gt; and &lt;code&gt;TWITTER_ACCESS_TOKEN_SECRET&lt;/code&gt; identify yourself. If that’s the case, you don’t really have to go through OAuth to identify yourself – we already generated those tokens for you (keep that in mind, it’s going to come in handy later).&lt;/p&gt;
&lt;h1&gt;
  
  
  Install Autohook
&lt;/h1&gt;

&lt;p&gt;Next, we’ll install Autohook. Its package is available from both npm and Yarn.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-S&lt;/span&gt; twitter-autohook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I almost wish there were more steps, but that’s it. Autohook is that easy!&lt;/p&gt;
&lt;h1&gt;
  
  
  Create a new project
&lt;/h1&gt;

&lt;p&gt;We’ll start with a new project. We’re setting it up in your home folder, but naturally it can live anywhere:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/autohook-tutorial
&lt;span class="nb"&gt;cd &lt;/span&gt;autohook-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s create a file named &lt;code&gt;index.js&lt;/code&gt;. We’ll add code to call Autohook and make sure everything is configured as intended. Just so we can start with a clean environment, this code will remove all existing webhooks from your environment. If you don’t want to lose your existing webhooks, choose a different dev environment from your developer dashboard. As an alternative, you can remove the call to &lt;code&gt;removeWebhooks()&lt;/code&gt;, and replace &lt;code&gt;start()&lt;/code&gt; with &lt;code&gt;startServer()&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Save and run your file. You should see something similar to this (note that your URL will be different, and so will be your subscribing username):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node index.js
Getting webhooks…
Removing webhooks…
Removing https://ce085a0d.ngrok.io/webhook…
Registering https://e3fd0ff6.ngrok.io/webhook as a new webhook…
Webhook created.
Subscribed to i_am_daniele&lt;span class="s1"&gt;'s activities.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Behind the scenes, Autohook handled OAuth for us. It also ran a development server with logic to create a webhook and to validate the &lt;a href="https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/securing-webhooks?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;CRC signature&lt;/a&gt;. And because we provided your access token/secret, it also subscribed your app to listen to your user’s activity (it did come in handy)!&lt;/p&gt;

&lt;p&gt;What can go wrong at this point? The most common pitfall is that the authenticating user won’t authenticate. Remember, users need to authorize your app before it can access their activity; if you’re trying to authenticate a test user (or even better, if you’re asking a friend to help you test your app), make sure they’re authenticating using Sign In With Twitter and the &lt;a href="https://developer.twitter.com/en/docs/basics/authentication/overview/3-legged-oauth.html?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;3-legged OAuth flow&lt;/a&gt;. Autohook’s got your back – you can find a &lt;a href="https://github.com/twitterdev/autohook/blob/master/test/listen.js" rel="noopener noreferrer"&gt;sample implementation on the project’s page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you bump into an error, most likely your credentials are not set correctly; check your &lt;code&gt;.env.twitter&lt;/code&gt; and try again. If you’re still stuck, come visit the &lt;a href="https://twittercommunity.com" rel="noopener noreferrer"&gt;Twitter Community forums&lt;/a&gt; and we’ll be more than happy to help you out!&lt;/p&gt;
&lt;h1&gt;
  
  
  Detect and filter incoming events
&lt;/h1&gt;

&lt;p&gt;Now that Autohook took care of the underlying wiring, it’s time to focus on our app logic. The Account Activity API can ping your webhook with &lt;a href="https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/overview.html?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;many activity types&lt;/a&gt;, so it’s important we only react to the activity type related to an incoming message.&lt;/p&gt;

&lt;p&gt;Since you’re using Autohook, you can listen to an incoming event listener – The event name is just &lt;code&gt;event&lt;/code&gt;. Add this right before the call to &lt;code&gt;removeWebhooks()&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;If you run your code now, nothing may seem to happen at first. But try and like a Tweet and something like this will show up in your Terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;received&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;for_user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;102010879991606016&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;favorite_events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;92274d54c83ff07669999a00cad3e835&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fri Aug 02 21:54:13 +0000 2019&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;timestamp_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1564782853144&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;favorited_status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
       &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Because your app subscribed to your user’s activities, we received that activity in realtime. The object is always starts with &lt;code&gt;for_user_id&lt;/code&gt;, which indicates a user ID (if you subscribe to multiple users, this is how you know which user this activity belongs to). The actual activity is described by a dictionary key. In this case, we received a key named &lt;code&gt;favorite_events&lt;/code&gt; because we just liked a Tweet. There are many activities, like &lt;code&gt;tweet_create_events&lt;/code&gt;, &lt;code&gt;follow_events&lt;/code&gt;, and &lt;code&gt;direct_message_events&lt;/code&gt; just to mention a few. In Autohook, these values will all be event keys in your event object from the listener. So if we want to listen to direct messages only, all we have to do is to explicitly detect those events:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direct_message_events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In this case, we will only process direct message events, and we’ll send the details to a function named &lt;code&gt;sayHi()&lt;/code&gt;. This function will process the event and shoot a DM back waving hi to any incoming direct message!&lt;/p&gt;

&lt;h1&gt;
  
  
  Say hi 👋
&lt;/h1&gt;

&lt;p&gt;We'll create a message to wave hi back to our friend who just messages us. But how do we know who’s the sender, and how can we be sure this message is directed to our account? Thankfully, the Direct Message event will contain full details about both parties involved in the conversation. You already have the OAuth credentials of the recipient (yourself), which is all you need to send a message back by means of &lt;code&gt;sayHi()&lt;/code&gt;. The logic for this function is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We’ll double check that the Direct Message event is valid and was intended for to your user. You don't really need to do this since this code will only work with your user credentials, but it will be useful to implement in case you want to expand your code to make it say hi for other accounts.&lt;/li&gt;
&lt;li&gt;We’ll only listen to incoming messages (outgoing messages generate an activity too, and we want to filter those out otherwise we’ll run into an infinite loop).&lt;/li&gt;
&lt;li&gt;We’ll say hi!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To check that the message is valid, we’ll need to check that the message object exists and contains a &lt;code&gt;message_create&lt;/code&gt; key. This key contains all the relevant details about the message, including the sender and recipient IDs, and the message itself. We’ll also check the sender and recipient’s details, and if they’re the same, it means you are sending a message to yourself. If this happens, the autoresponder we’ll say hi to you, which in turn will cause the autoresponder to say hi to you, which in turn will cause the autoresponder to say hi to you… causing an infinite loop. It’s actually easier done than said:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// We check that the message is a direct message&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direct_message_events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Messages are wrapped in an array, so we'll extract the first element&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direct_message_events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// We check that the message is valid&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_create&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// We filter out message you send, to avoid an infinite loop&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All we have to do next is to prepare the request body for the message reply and send it as using the Direct Messages API. The request body of this API has the exact &lt;a href="https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/guides/message-create-object?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;same format of an Account Activity message response&lt;/a&gt;, which makes it easy to consume and produce.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Prepare and sent the message reply&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;senderScreenName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender_id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;screen_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.twitter.com/1.1/direct_messages/events/new.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;oAuthConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message_create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message_create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;message_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hi @&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;senderScreenName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;! 👋`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This is it! Run your code and ask a friend to send you a message. You should see an incoming message, followed by an automated direct message:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wvt3g2ghe6iw04og14u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wvt3g2ghe6iw04og14u.png" width="800" height="798"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Mark as read and typing indicator
&lt;/h1&gt;

&lt;p&gt;Our code so far is about 80 lines of code, so we have plenty of room to implement all the fancy things an autoresponder can do. Direct Messages on Twitter can indicate when a message has been read (it’s the blue check next to the message timestamp). Since our autoresponder will read an incoming message for us, it would be nice to tell the sender our autoresponder read our message and that it’s about to reply.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglucjoc8o155sujux2rf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglucjoc8o155sujux2rf.png" width="566" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the message body doesn’t have to be sophisticated, you will send these POST requests as form encoded, rather than sending raw JSON data like we did before. &lt;/p&gt;

&lt;p&gt;To get the read check mark, we’ll simply extract the message ID from the activity we received earlier. Just like before, we’ll create the appropriate request body to send it to the &lt;a href="https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-read-receipt?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;Mark Read&lt;/a&gt; endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;markAsRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.twitter.com/1.1/direct_messages/mark_read.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;last_read_event_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Similarly, we’ll now display a typing indicator which will present in the Direct Message window as a bubble with three dots. Since this is just an animation, there is no message attached to it; we will simply need to pass the ID of the person we want to show this bubble to the &lt;a href="https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-typing-indicator?utm_source=autohook_tutorial_devto&amp;amp;utm_medium=devto&amp;amp;utm_campaign=autohook_tutorial" rel="noopener noreferrer"&gt;Indicate Typing API call&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;indicateTyping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.twitter.com/1.1/direct_messages/indicate_typing.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;recipient_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;senderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You're all set! The complete code should look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h1&gt;
  
  
  Time to say bye
&lt;/h1&gt;

&lt;p&gt;And there you have it! Because you didn’t have to deal with the complexity of webhooks and authentication, you may have noticed that you just wrote the entire code in less than 100 lines! This has been a quick and easy way to explore the power of the Account Activity API, and a great starting point for your next 100 lines of code.&lt;/p&gt;

</description>
      <category>twitter</category>
      <category>api</category>
      <category>webhooks</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
