- product:voice - sdk:compatibility - language:python - language:php - language:nodejs # Gathering User Input from Code In [Gathering User Input](guides/voice-api/getting-started-with-voice/how-to-gather-keypad-input-from-user.mdx) we showed how to set up an XML bin to collect input from users. The approach we showed had a limitation: we couldnt _take choices_ based on the users input. In this article, we are going to see how to build an input-gathering application using Compatibility XML and SDKs. Using the SDKs will allow us to perform complex choices. For the sake of this guide, we are going to build a very simple IVR. :::info Prerequisites We will take for granted that you know how to set up a basic application using the Compatibility SDKs. If not, make sure to read [Handling Calls from Code](./handling-calls-from-code/index.mdx) first. ::: ## Entrypoint Wed like to offer callers a set of choices, such as: - Press (1) to speak with Support - Press (2) to speak with Sales - Press (3) to speak with Marketing We can implement this using the [](/compatibility-api/cxml/voice/gather) verb. The following is the XML that wed like to use as entry point: xml Welcome! Please press 1 to speak with Support. Press 2 to speak with Sales. Press 3 to speak with Marketing. We did not receive any input. Goodbye! Instead of using this XML document directly (for example as a hosted XML bin), in this case we are going to generate it from our server. Lets define an endpoint at /: python title=main.py from flask import Flask, request, Response from twilio.twiml.voice_response import VoiceResponse, Gather app = Flask(__name__) @app.route(/, methods=[GET, POST]) def call_handler(): This endpoint will be queried by SignalWire whenever an incoming call is received. We respond with an XML document which specifies the next instructions. response = VoiceResponse() gather = Gather(action=https://example.com/choice, method=POST, numDigits=1) gather.say(Welcome! Please press 1 to speak with Support. + Press 2 to speak with Sales. + Press 3 to speak with Marketing.) response.append(gather) response.say(We did not receive any input. Goodbye!) return Response(response.to_xml(), mimetype=text/xml) php title=index.php gather(array( action => https://example.com/choice.php, method => POST, numDigits => 1 )); $gather->say(Welcome! Please press 1 to speak with Support. . Press 2 to speak with Sales. . Press 3 to speak with Marketing.); $response->say(We did not receive any input. Goodbye!); header(Content-type: text/xml); echo $response->asXML(); javascript title=index.js import express from express; import { RestClient } from @signalwire/compatibility-api; const app = express(); app.use(express.urlencoded({ extended: true })); /** * @param {express.Request} req * @param {express.Response} res */ function callHandler(req, res) { // This endpoint will be queried by SignalWire whenever an incoming call is received. // We respond with an XML document which specifies the next instructions. const response = new RestClient.LaML.VoiceResponse(); const gather = response.gather({ action: https://example.com/choice, method: POST, numDigits: 1, }); gather.say( Welcome! Please press 1 to speak with Support. + Press 2 to speak with Sales. + Press 3 to speak with Marketing. ); response.say(We did not receive any input. Goodbye!); res.set(Content-Type, text/xml); res.send(response.toString()); } app.get(/, callHandler); app.post(/, callHandler); app.listen(8088); As soon as the user inputs a number, we execute the XML script at https://example.com/choice. This is an endpoint which will receive the user input as an HTTP parameter, and will emit new XML: make sure to replace this URL with your actual public URL (for example, the ngrok URL). Keep the /choice path though: we are going to show the implementation for this endpoint in the next section. ## Branching After the user makes a choice, SignalWire will fetch our server at /choice including the input as parameter. Lets implement the /choice endpoint to read the input and reply accordingly. python title=main.py # ... previous code @app.route(/choice, methods=[GET, POST]) def choice_handler(): choice = request.values.get(Digits) response = VoiceResponse() if choice == 1: response.say(You selected: support) elif choice == 2: response.say(You selected: sales) elif choice == 3: response.say(You selected: marketing) else: response.say(Invalid input. Please try again.) response.redirect(https://example.com/) return Response(response.to_xml(), mimetype=text/xml) php title=choice.php say(You selected: support); } else if ($choice == 2) { $response->say(You selected: sales); } else if ($choice == 3) { $response->say(You selected: marketing); } else { $response->say(Invalid input. Please try again.); $response->redirect(https://example.com/); } header(Content-type: text/xml); echo $response->asXML(); javascript title=index.js // ... previous code /** * @param {express.Request} req * @param {express.Response} res */ function choiceHandler(req, res) { /** @type string */ const choice = req.body?.[Digits] ?? ; const response = new RestClient.LaML.VoiceResponse(); if (choice === 1) { response.say(You selected: support); } else if (choice === 2) { response.say(You selected: sales); } else if (choice === 3) { response.say(You selected: marketing); } else { response.say(Invalid input. Please try again.); response.redirect(https://example.com/); } res.set(Content-Type, text/xml); res.send(response.toString()); } app.post(/choice, choiceHandler); app.listen(8088); This time, we read the Digits parameter and we reply with a different message depending on its value. If the value is not one of the expected ones, we let the user try again by redirecting the script to the initial endpoint /: make sure to replace https://example.com/ with your actual public URL. After configuring one of your numbers to handle incoming calls using the webhook that we implemented, you will be able to test the application. Refer to [Handling Calls from Code](./handling-calls-from-code/index.mdx) to learn how to configure your number. ## Conclusion We have shown how to gather input from the user, and take decisions accordingly. We did all this in the context of the [Compatibility API](pathname:///compatibility-api). For more advanced, real-time applications, youll want to check out our [Realtime SDK](sdks/reference/realtime-sdk/relay-v3/00-realtime-sdk-reference.mdx). Find more details in the guide about [First Steps with Voice in the Realtime SDK](guides/voice-api/guides/realtime-api/first-steps-with-voice/index.mdx).