# Send user prompts Learn how to let external systems request input from the store colleague during payment processing when using custom payment integrations. User prompts allow you to trigger a dialog in the payment UI to request input or confirmation from the store colleague completing the sale. InStore displays a configurable dialog with custom messages and button options, and returns the colleague's input to your endpoint. User prompts are useful for resolving mid-payment issues with the PED without interrupting the asynchronous payment process. For example, when the printer is out of paper and the colleague must replace it before continuing the payment. ## Send a user prompt To display a prompt to the user, include a `prompt` object in the `status` update message from the payment extension. The object includes the following parameters: | Parameter | Description | | --- | --- | | `type` | Must be set to `prompt` to trigger a user dialog. | | `keepAlive` | (Optional) Time in milliseconds to extend the session timeout. | | `requestId` | (Optional) Unique identifier for tracking this request. | | `message` | Body of text to display on the dialog box. | | `title` | (Optional) Title text for the dialog box. | | `options` | Array of button options to present to the user. | | `text` | Button label displayed to the user. | | `response` | Value returned when this option is selected. | | `primary` | (Optional) Set to `true` to style this as the primary button, which is highlighted and auto-focused. | ```js title="Example prompt object" await sendStatus(statusUrl, { type: "prompt", keepAlive: 20000, // reset timeout to 20 seconds requestId: "unique-request-id-123", // Optional: provide a unique ID to track this specific request message: "The PED printer is out of paper. Please add paper and press OK to continue", title: "Printer Error", // Optional: dialog title options: [ { text: "Cancel", // Button text displayed to the user response: "Cancel" // Response value sent back to your system }, { text: "OK", response: "Continue", primary: true // Mark this option as the primary action (highlighted button) } ] }); ``` ## Receive user responses When the user selects an option, InStore sends a `POST` request to your endpoint with the path suffix `/user-response`. The payload contains a `requestId` and a `response` ```js title="Example response payload" { requestId: "unique-request-id-123", // The requestId provided in your prompt response: "Continue" // The response value from the selected option } ``` ## Response handling Make sure your endpoint does the following to handle the response: 1. Accept the `POST` request with the response payload. 2. Process the response accordingly, such as continuing the transaction or canceling. 3. Return a `200` status code to acknowledge successful receipt. ## Example implementation The following example sends a prompt indicating that the payment device is low on paper: ```js title="Example prompt request and response handling" const promptUser = async () => { try { const result = await sendStatus(statusUrl, { type: "prompt", requestId: "paper-low-" + transactionId, message: "The PED printer is low on paper. Continue with transaction?", title: "Low Paper Warning", options: [ { text: "Cancel Transaction", response: "Cancel", }, { text: "Continue Anyway", response: "Continue", primary: true } ] }); // Handle send status result if needed return result; } catch (error) { console.error("Failed to send user prompt:", error); // Handle error appropriately } }; ``` In the sample code, the server waits 10 seconds after receiving the prompt request, then sends the default response regardless of the user's action. Override this in your web server with the following code: ```js title="Example override" // In your Express.js or similar web server: app.post('/payment/user-response', (req, res) => { const { requestId, response } = req.body; console.log(`Received user response: ${response} for request: ${requestId}`); // Process the response based on requestId and response value if (requestId.startsWith('paper-low-') && response === 'Continue') { // User chose to continue despite low paper continueTransaction(requestId.split('-')[2]); } else if (response === 'Cancel') { // User chose to cancel cancelTransaction(requestId); } // Acknowledge receipt res.status(200).send({ status: 'ok' }); }); ``` ## Best practices For best results, we recommend the following: - Add meaningful messages that provide clear, concise instructions in your prompts. - Use unique request IDs for each prompt, for ease in tracking responses. - Consider the appropriate `keepAlive` values to prevent session timeouts. - Use the `primary` flag to highlight the recommended or safe action. - Ensure your endpoint is ready to receive and process responses. ## Troubleshooting If you don't receive a response to your request, check the following: - Is your endpoint correctly registered and accessible? - Are your prompt message and button options correctly formatted? - Does your endpoint handle the response payload correctly? ## Related pages - [Area overview page with navigation](/instore.md) - [Search documentation and API specs](/search.md)