---slug: /guides/voice/compatibility-api/gathering-user-input-from-codex-custom: author: danieleds---# Gathering User Input from Codeimport Tabs from @theme/Tabs;import TabItem from @theme/TabItem;In [Gathering UserInput](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 weshowed 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 applicationusing Compatibility XML and SDKs. Using the SDKs will allow us to performcomplex choices. For the sake of this guide, we are going to build a very simple IVR.:::info PrerequisitesWe will take for granted that you know how to set up a basic application usingthe Compatibility SDKs. If not, make sure to read [Handling Calls fromCode](./handling-calls-from-code/index.mdx) first.:::## EntrypointWed 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 MarketingWe can implement this using the [](pathname:///compatibility-api/xml/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 anendpoint at /:python title=main.pyfrom flask import Flask, request, Responsefrom twilio.twiml.voice_response import VoiceResponse, Gatherapp = 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.phpgather(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.jsimport 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 athttps://example.com/choice. This is an endpoint which will receive the userinput as an HTTP parameter, and will emit new XML: make sure to replace this URLwith your actual public URL (for example, the ngrok URL). Keep the /choicepath though: we are going to show the implementation for this endpoint in thenext section.## BranchingAfter the user makes a choice, SignalWire will fetch our server at /choiceincluding the input as parameter. Lets implement the /choice endpoint to readthe 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.phpsay(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 messagedepending on its value. If the value is not one of the expected ones, we let theuser try again by redirecting the script to the initial endpoint /: make sure toreplace https://example.com/ with your actual public URL.After configuring one of your numbers to handle incoming calls using the webhookthat 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 toconfigure your number.## ConclusionWe 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 outour [Realtime SDK](sdks/reference/realtime-sdk/00-realtime-sdk-reference.mdx). Find more detailsin the guide about [First Steps with Voice in the Realtime SDK](guides/voice-api/guides/realtime-api/first-steps-with-voice/index.mdx).