> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.moveworks.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.moveworks.com/_mcp/server.

# Get modal

GET https://api.moveworks.ai/rest/v1/conversations/{conversation_id}/responses/{response_id}/messages/{message_id}/modals/{modal_id}

Retrieves the definition of a modal surfaced by a `MODAL_ACTION` on an assistant message, so that your application can render it natively.

Every path parameter comes from that message. An entry in its `actions` array whose `type` is `MODAL_ACTION` carries the `modal_id` as `modal_action.modal_id`, and the message itself supplies `conversation_id`, `response_id`, and `message_id`. Assistant messages arrive from the list-messages endpoints, the get-response endpoint, and the `RESPONSE_OUTPUT_DELTA` and `RESPONSE_COMPLETED` streaming events.

Conditional field rules are evaluated server-side, so every field arrives with its initial `visible`, `required`, and `read_only` state already resolved. Render the fields in the order they are returned. Fields whose value can change another field's state are flagged with `triggers_refresh`; call the refresh endpoint after one of those values changes.

Keep the `options` list of every choice field in your own state. It is returned here and is not repeated on the refresh response.

Reference: https://docs.moveworks.com/api-reference/conversations-api/conversations-api/modals/get-modal

## Authentication

- `Authorization` header (bearer token, required) — JWT bearer token authentication. Obtain an access token from the Moveworks auth endpoint and include it in the Authorization header as 'Bearer \<token>'.

## Request

### Path parameters

- `conversation_id` (string, required) — A base-62 identifier prefixed by a short resource type
- `response_id` (string, required) — A base-62 identifier prefixed by a short resource type
- `message_id` (string, required) — A base-62 identifier prefixed by a short resource type
- `modal_id` (string, required) — Opaque modal identifier, taken from the `modal_action.modal_id` of the action that surfaced this modal. Pass it back exactly as received.

### Headers

- `Assistant-Name` (string, required) — The Moveworks assistant identifier that was configured for your organization.

## Response

### 200

Modal retrieved successfully

- `modal_id` (string, required) — Opaque modal identifier, echoed from the `MODAL_ACTION` that surfaced this modal.
- `title` (string, required) — Modal title to display.
- `fields` (list of object, required) — Fields in display order. Render them in the order returned.
  - `type` (enum, required) — Field kind discriminator. Determines which type-specific payload is present on the field, and which value shape it accepts on submit.
    - Allowed values: `TEXT`, `DATE`, `DATETIME`, `BOOLEAN`, `CHOICE`, `FILE`, `DISPLAY`
  - `name` (string, optional) — Stable submission key, unique within the modal. Opaque to clients: it may contain dots (for example `form_data.priority`) and must be echoed verbatim as the `values` map key on refresh and submit. Absent on `DISPLAY` blocks, which are never submitted.
  - `label` (string, optional) — Label to display for the field.
  - `description` (string, optional) — Help text describing how to fill the field.
  - `required` (boolean, optional) — A value must be submitted for this field.
  - `visible` (boolean, optional) — Whether to show the field to the user. Fields that resolve to hidden are neither required nor persisted.
  - `read_only` (boolean, optional) — Field is display-locked: render the value but reject edits.
  - `triggers_refresh` (boolean, optional) — Changing this field's value can change other fields' state. Call the refresh endpoint after the value changes, and re-render from the modal it returns. Submitting a modal whose flagged field changed without an intervening refresh can fail validation.
  - `text` (object, optional) — Free text, single-line or multiline.
    - `multiline` (boolean, optional) — Render as a textarea rather than a single-line input.
    - `prefill` (string, optional) — Initial value, user-editable. Often drafted from the conversation, and submitted as-is if the user does not change it.
  - `date` (object, optional) — Calendar date, with no time and no timezone. A `DATE` is never widened to a `DATETIME` on submit.
    - `prefill` (date, optional) — Initial calendar date as `YYYY-MM-DD`.
  - `datetime` (object, optional) — An instant in time.
    - `prefill` (datetime, optional) — Initial instant as an RFC 3339 timestamp, in UTC or with an explicit offset.
  - `boolean` (object, optional) — A toggle. It has no unanswered state, so an untouched field submits `false`.
    - `prefill` (boolean, optional) — Initial toggle state.
  - `choice` (object, optional) — Selection from a set of options, single or multiple.
    - `multi` (boolean, optional) — Allow more than one selection. Single-select submits `option`, multi-select submits `options`.
    - `options` (list of object, optional) — Selectable options in display order. Returned when the modal is first retrieved. The refresh endpoint omits it, so keep the options in your own state and re-apply them to the refreshed field.
      - `value` (string, required) — The value to submit for this option.
      - `display_value` (string, required) — Label to show the user. Never submitted.
    - `allows_free_input` (boolean, optional) — Accept a submitted value that is not in `options`, skipping membership validation. Typical for "type to search, or enter your own".
    - `prefill` (list of object, optional) — Initially selected options. Holds at most one entry when `multi` is `false`.
      - `value` (string, required) — The value to submit for this option.
      - `display_value` (string, required) — Label to show the user. Never submitted.
  - `file` (object, optional) — File upload, submitted by handle rather than by bytes.
    - `max_files` (integer, required) — Maximum number of files. Submitting more fails validation.
  - `display` (object, optional) — Display-only block interleaved with the input fields. Exactly one of `text`, `image`, or `download` is present. Never required, never submitted, and never present in a `values` map.
    - `text` (object, optional)
      - `text` (string, required) — Text to display.
      - `style` (enum, optional) — Rendering treatment for a display text block. `NORMAL` is regular body text and supports CommonMark, `HEADER` is a large bold heading, `SUBTLE` is a small gray caption.
        - Allowed values: `NORMAL`, `HEADER`, `SUBTLE`
    - `image` (object, optional)
      - `url` (string, required) — URL of the image to display.
    - `download` (object, optional)
      - `url` (string, required) — URL of the file to download.
      - `text` (string, optional) — Link text to display.

## Examples

**Response**

```json
{
  "modal_id": "eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ",
  "title": "File an IT ticket",
  "fields": [
    {
      "type": "DISPLAY",
      "visible": true,
      "display": {
        "text": {
          "text": "We will route this to the IT service desk.",
          "style": "SUBTLE"
        }
      }
    },
    {
      "type": "TEXT",
      "name": "short_description",
      "label": "Short description",
      "description": "One line summarizing the problem.",
      "required": true,
      "visible": true,
      "read_only": false,
      "triggers_refresh": false,
      "text": {
        "multiline": false,
        "prefill": "Laptop will not connect to the VPN"
      }
    },
    {
      "type": "CHOICE",
      "name": "priority",
      "label": "Priority",
      "required": true,
      "visible": true,
      "read_only": false,
      "triggers_refresh": true,
      "choice": {
        "multi": false,
        "options": [
          {
            "value": "low",
            "display_value": "Low"
          },
          {
            "value": "high",
            "display_value": "High"
          }
        ],
        "allows_free_input": false,
        "prefill": [
          {
            "value": "low",
            "display_value": "Low"
          }
        ]
      }
    },
    {
      "type": "TEXT",
      "name": "business_impact",
      "label": "Business impact",
      "description": "Required for high priority tickets.",
      "required": false,
      "visible": false,
      "read_only": false,
      "triggers_refresh": false,
      "text": {
        "multiline": true
      }
    },
    {
      "type": "FILE",
      "name": "screenshots",
      "label": "Screenshots",
      "required": false,
      "visible": true,
      "read_only": false,
      "triggers_refresh": false,
      "file": {
        "max_files": 3
      }
    }
  ]
}
```

**SDK Code**

```python Modals_getModal_example
import requests

url = "https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ"

headers = {
    "Assistant-Name": "acmecorp-conversations-rest-api",
    "Authorization": "Bearer <token>"
}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript Modals_getModal_example
const url = 'https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ';
const options = {
  method: 'GET',
  headers: {
    'Assistant-Name': 'acmecorp-conversations-rest-api',
    Authorization: 'Bearer <token>'
  }
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Modals_getModal_example
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Assistant-Name", "acmecorp-conversations-rest-api")
	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Modals_getModal_example
require 'uri'
require 'net/http'

url = URI("https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Assistant-Name"] = 'acmecorp-conversations-rest-api'
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java Modals_getModal_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ")
  .header("Assistant-Name", "acmecorp-conversations-rest-api")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php Modals_getModal_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ', [
  'headers' => [
    'Assistant-Name' => 'acmecorp-conversations-rest-api',
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp Modals_getModal_example
using RestSharp;

var client = new RestClient("https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ");
var request = new RestRequest(Method.GET);
request.AddHeader("Assistant-Name", "acmecorp-conversations-rest-api");
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift Modals_getModal_example
import Foundation

let headers = [
  "Assistant-Name": "acmecorp-conversations-rest-api",
  "Authorization": "Bearer <token>"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.moveworks.ai/rest/v1/conversations/conv_32bt7BMLhLyVzTUjfi35N/responses/resp_32bt7rXXugeJjvE3pQzOk/messages/msg_32bt8vagXAoRwRLIdI2Oj/modals/eyJtb2RhbF9pZCI6Imluc2lkZW50X2Zvcm0ifQ")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```