# Widgets API reference

Manage widget placement, visibility, responsive design options, and flow connections in the project draft.

Available on the Scale and Pro plans.

Use widgets to choose how and where a flow appears. The API returns the stored design settings, not a rendered preview.

## Authentication and widget operations

Paths below follow `https://api.rightmessage.com/v1/{teamPid}`. GET requires `read` or `write`; mutations require `write`. The `*` ability satisfies both. The [shared request conventions](https://rightmessage.com/help/rest-api-overview#base-url-and-authentication) cover bearer authentication, headers, project access, and rate limits.

| Method and path                  | Request                             | Success                    |
| -------------------------------- | ----------------------------------- | -------------------------- |
| GET `/widgets`                   | No filters or pagination parameters | 200, `{"data":[RESOURCE]}` |
| GET `/widgets/{widget}`          | Resource ID from the list           | 200, `{"data":RESOURCE}`   |
| POST `/widgets`                  | Create body below                   | 201, `{"data":RESOURCE}`   |
| PUT or PATCH `/widgets/{widget}` | Partial body below                  | 200, `{"data":RESOURCE}`   |
| DELETE `/widgets/{widget}`       | No body                             | 204, empty body            |

PUT and PATCH have the same partial-update behavior. An omitted top-level field retains its value. A collection with no resources returns `{"data":[]}`. Reads return the draft when one exists, otherwise the stable configuration.

## Errors and draft effects

The [shared error contract](https://rightmessage.com/help/rest-api-overview#error-contract) applies. Invalid request fields return 422 with `message` and field-keyed `errors`. Full-configuration validation can return 500 instead.

Mutations save a draft, not live changes. [Publishing](https://rightmessage.com/help/rest-api-publishing) applies the whole project draft, including edits made elsewhere. The [draft contract](https://rightmessage.com/help/rest-api-overview#draft-and-live-configuration) covers snapshots, dashboard updates, and save failures.

## Widget request fields

Only `name` is required on create. All fields are optional on update.

| Field                   | Validation                                                                  | Create default                                            |
| ----------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------- |
| `name`                  | Nonempty string, maximum 255                                                | Required                                                  |
| `type`                  | `modal`, `bar`, `toaster`, `inline`, or `takeover`                          | modal                                                     |
| `flow_id`               | Nullable string. Nonempty IDs must name an existing flow.                   | null                                                      |
| `is_enabled`            | Boolean                                                                     | true                                                      |
| `frequency`             | `startover`, `immediately`, `pageview`, `session`, or `none`                | session                                                   |
| `visibility`            | Object                                                                      | Conditions null, trigger exitIntent, dismiss rule session |
| `visibility.conditions` | Nullable logic object                                                       | null                                                      |
| `visibility.trigger`    | Nullable string at request validation. The stored schema requires a string. | exitIntent                                                |
| `options`               | Design object below                                                         | Default plain design                                      |

Visibility updates merge supplied keys. Design updates recursively replace supplied keys while preserving omitted nested keys. These are not whole-object replacements.

## Visibility and inline placement

`visibility` also passes through these stored keys:

| Key                  | Contract                                                                                                                                                                                                                                                    |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `areas`              | String naming embed areas.                                                                                                                                                                                                                                  |
| `placements`         | Array of closed objects requiring nonblank string `path`, nonblank string `selector`, and `position` of `inside`, `before`, or `after`. Optional `domain` is a bare hostname, maximum 253 characters. No scheme, path, port, or wildcard. Stored lowercase. |
| `dismissRule`        | Object with `type` of `session`, `duration`, or `forever`; optional numeric `duration`; optional `unit` of `minutes`, `hours`, `days`, or `weeks`. Type defaults session.                                                                                   |
| `instantDismiss`     | Boolean, default false in the configuration schema.                                                                                                                                                                                                         |
| `formSubmitSelector` | Open stored value. No dedicated type rule.                                                                                                                                                                                                                  |

A new inline widget needs a nonblank `areas` string or at least one complete placement. Placements are valid only for inline widgets. To change an inline widget to another type, clear placements with `[]` in the same request. Invalid placements return 422.

The following legacy keys must be absent, even when false or empty: `show_on_specific_pages`, `show_pages`, `hide_on_specific_pages`, `hide_pages`, `isWhitelistEnabled`, `whitelist`, `isBlacklistEnabled`, and `blacklist`. They return 422 with guidance to use `visibility.conditions`.

Logic objects accept recursive `and`, `or`, and `not`. Answer conditions use the [question condition contract](https://rightmessage.com/help/rest-api-questions).

The API's default trigger, `exitIntent`, does not match the visitor runtime, which expects `exit`. Scroll and time triggers also require a threshold, such as `scroll_50pc` or `time_5s`, rather than bare `scroll` or `timed`. Set a supported trigger explicitly for non-inline widgets. See the [runtime trigger values](https://rightmessage.com/help/mcp-tools-widgets#trigger-values-and-the-creation-default). Publishing does not correct this API-default mismatch.

## Design options

All options are optional. `custom_css` aliases `customCss`, and `display_targets` aliases `displayTargets`. An alias overrides its camelCase counterpart when both are supplied. Responses use camelCase. The overall options object permits additional keys, but declared fields still undergo schema validation.

| Top-level key                                                                                               | Type and contract                                                        |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `theme`, `font`, `customCss`, `placement`, `backButtonLabel`, `backButtonEnabled`, `buttonAnimationTrigger` | Open schema values; the validator does not enforce a type.               |
| `headingFont`                                                                                               | String or null                                                           |
| `darkMode`                                                                                                  | `off` or `auto`                                                          |
| `typeScale`                                                                                                 | `s`, `m`, `l`, or `custom`                                               |
| `nextButtonLabel`, `skipButtonLabel`                                                                        | Strings, default Next and Skip                                           |
| `palette`, `paletteDark`                                                                                    | Color settings below; paletteDark accepts null                           |
| `fontSize`, `structure`, `look`                                                                             | Nested settings below                                                    |
| `headerInfo`                                                                                                | Open values at `isEnabled`, `style`, `imageUrl`, `title`, and `subtitle` |
| `progressBar`                                                                                               | Open values at `isEnabled` and `baseColor`                               |
| `displayTargets`                                                                                            | Open values at `phones`, `tablets`, and `desktop`; each starts true      |
| `style`                                                                                                     | Open `shadowSize` value                                                  |
| `overrides`                                                                                                 | Closed object accepting only `phone` and `tablet` device overrides       |

### Palette

`palette` starts with `borderColor: "#e2e8f0"`, `contrastColor: "#3b82f6"`, `backgroundColor: "#ffffff"`, `textOnContrastColor: "#ffffff"`, and `textOnBackgroundColor: "#1e293b"`. Those five keys have open value schemas in the light palette and require strings in `paletteDark`.

Both palettes accept nullable strings for `answerButtonColor`, `textOnAnswerButtonColor`, `formFieldColor`, `formFieldTextColor`, `formFieldBorderColor`, `placeholderColor`, `linkColor`, `backdropColor`, `backgroundGradientFrom`, `backgroundGradientTo`, `questionHeadingColor`, `questionTextColor`, `offerHeadingColor`, `offerTextColor`, `headerTitleColor`, and `headerSubtitleColor`. `backdropOpacity` is a number from 0 through 1 or null.

### Font sizes

`fontSize` has open values for `lineHeight`, `headlineFontSize`, `formFieldFontSize`, `descriptionFontSize`, `answerButtonFontSize`, and `submitButtonFontSize`.

`headingFontWeight`, `bodyFontWeight`, and `buttonFontWeight` are numbers from 400 through 900 or null. `submitButtonFontWeight` also accepts `theme`. `headerTitleFontSize` and `headerSubtitleFontSize` accept null or nonnegative pixel strings such as `18px` or `18.5px`.

### Structure

Open values are `formFieldSpacing`, `buttonBorderRadius`, `answerButtonSpacing`, `containerBorderWidth`, `containerBorderRadius`, and `widgetWidth`.

Nullable nonnegative pixel strings are `submitButtonBorderRadius`, `fieldBorderRadius`, `imageHeight`, `backdropBlur`, `containerPaddingY`, `containerPaddingX`, `titleSpacing`, `contentSpacing`, `submitSpacing`, and `headerSpacing`. `buttonLetterSpacing` and `submitButtonLetterSpacing` accept null or signed `em` strings, such as `0.02em` or `-0.02em`.

### Look

| Key                                | Accepted values                                            |
| ---------------------------------- | ---------------------------------------------------------- |
| `density`                          | compact, comfortable, spacious, custom, null               |
| `buttonStyle`, `submitButtonStyle` | solid, outline, ghost, gradient, null                      |
| `buttonSize`, `submitButtonSize`   | s, m, l, null                                              |
| `buttonFullWidth`                  | Boolean or null                                            |
| `submitButtonFullWidth`            | Boolean, theme, or null                                    |
| `buttonUppercase`                  | Boolean                                                    |
| `submitButtonUppercase`            | Boolean or null                                            |
| `buttonHover`                      | darken, lighten, lift, none, null                          |
| `submitButtonHover`                | theme, darken, lighten, lift, none, null                   |
| `fieldStyle`                       | boxed, underlined, filled, null                            |
| `labelPosition`                    | above, inside, hidden, null                                |
| `borderStyle`                      | solid, dashed, dotted                                      |
| `backgroundType`                   | color, gradient, image                                     |
| `backgroundGradientAngle`          | Number 0 through 360, or null                              |
| `backgroundImageUrl`               | String or null                                             |
| `imagePosition`                    | top, left, background, null                                |
| `entrance`                         | none, fade, slide, scale, null                             |
| `entranceSpeed`                    | slow, normal, fast                                         |
| `stepTransition`                   | slideLeft, slideUp, slideDown, crossfade, zoom, none, null |
| `stepTransitionFade`               | Boolean or null                                            |
| `closeButtonStyle`                 | icon, circle, text, null                                   |
| `closeButtonPosition`              | left, right, null                                          |
| `backButtonStyle`                  | link, button, icon, null                                   |
| `skipButtonStyle`                  | link, button, null                                         |

### Device overrides

Each `overrides.phone` or `overrides.tablet` is closed and accepts only `fontSize`, `structure`, and `look`. Their child objects are also closed.

Device `fontSize` accepts the same keys listed above. Unlike the base object, `lineHeight` must be numeric. `headlineFontSize`, `formFieldFontSize`, `descriptionFontSize`, `answerButtonFontSize`, and `submitButtonFontSize` must be strings. Weight and header-size constraints remain unchanged.

Device `structure` accepts the same keys listed above. The formerly open values require strings, except `widgetWidth`, which also accepts null. Pixel and letter-spacing constraints remain unchanged.

Device `look` accepts only `density`, `buttonSize`, `buttonFullWidth`, `submitButtonSize`, and `submitButtonFullWidth`, with the same value constraints as the base object.

Invalid declared design values return 422 under `errors.options` before the full configuration save. This differs from malformed nested configuration elsewhere, which can reach a 500.

## Widget responses and limitations

The response contains `id`, `name`, `type`, `is_enabled`, `flow_id`, `frequency`, `visibility`, and `options`. It serializes only `conditions` and `trigger` inside visibility. Placement, area, and dismissal settings are saved but are not echoed there. Do not use that reduced visibility response as proof that an inline widget has no placement.

New IDs use `wdg_`. The service starts with theme `plain`, empty `customCss`, and the palette above. Configuration repair then fills omitted typography, structure, header, progress-bar, and look values; it also supplies `paletteDark: null`, `headingFont: null`, and `typeScale: "custom"`. These defaults can depend on widget type, so read the returned options rather than assuming the small create payload is the complete design. Deletion removes the widget only; its flow remains.

## Illustrative requests and responses

These illustrative examples use the fictional WorkForge project. The same resource schema covers every CRUD response.

```http
GET /v1/123456/widgets HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

GET /v1/123456/widgets/wdg_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

POST /v1/123456/widgets HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge welcome",
	"type": "modal",
	"visibility": {"trigger": "exit"},
	"options": {
		"theme": "plain"
	}
}

PATCH /v1/123456/widgets/wdg_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge updated"
}

DELETE /v1/123456/widgets/wdg_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
```

The PATCH example also works with PUT. The create, item-read, and update envelopes have this shape. This response is an excerpt: `options` also contains the repair-added settings described above. The list places resource objects in its `data` array. An update returns updated values. DELETE returns no JSON.

```json
{
	"data": {
		"id": "wdg_example1",
		"name": "WorkForge welcome",
		"type": "modal",
		"is_enabled": true,
		"flow_id": null,
		"frequency": "session",
		"visibility": {
			"conditions": null,
			"trigger": "exit"
		},
		"options": {
			"theme": "plain",
			"palette": {
				"borderColor": "#e2e8f0",
				"contrastColor": "#3b82f6",
				"backgroundColor": "#ffffff",
				"textOnContrastColor": "#ffffff",
				"textOnBackgroundColor": "#1e293b"
			},
			"customCss": "",
			"nextButtonLabel": "Next",
			"skipButtonLabel": "Skip",
			"displayTargets": {
				"phones": true,
				"tablets": true,
				"desktop": true
			}
		}
	}
}
```
