# Offers API reference

Manage calls to action, content, link destinations, and supported provider actions through the public REST API.

Available on the Scale and Pro plans.

Use offers to configure calls to action in a flow. Saving an offer defines what happens later on your site. It does not submit a contact or execute a provider action during the API request.

## Authentication and offer 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 `/offers`                  | No filters or pagination parameters | 200, `{"data":[RESOURCE]}` |
| GET `/offers/{offer}`          | Resource ID from the list           | 200, `{"data":RESOURCE}`   |
| POST `/offers`                 | Create body below                   | 201, `{"data":RESOURCE}`   |
| PUT or PATCH `/offers/{offer}` | Partial body below                  | 200, `{"data":RESOURCE}`   |
| DELETE `/offers/{offer}`       | 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.

## Offer request fields

Only `name` is required on create. Every other field is optional, and every field is optional on update.

| Field               | Type and limits                                            | Create default |
| ------------------- | ---------------------------------------------------------- | -------------- |
| `name`              | Nonempty string, maximum 255                               | Required       |
| `is_enabled`        | Boolean                                                    | true           |
| `parts`             | Object                                                     | Defaults below |
| `parts.title`       | String, maximum 500                                        | Untitled Offer |
| `parts.description` | Nullable string                                            | null           |
| `parts.button_text` | Nullable string, maximum 255                               | Learn More     |
| `parts.image_url`   | Nullable string, maximum 2,000                             | null           |
| `action`            | Object                                                     | Link action    |
| `action.type`       | `link`, `tag`, `event`, `automation`, `list`, or `contact` | link           |
| `action.settings`   | Object                                                     | Empty object   |

The following keys belong inside `action.settings`.

| Key                        | Type and behavior                                                                                                                                                                             |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`                      | Nullable string, maximum 2,000. Link destination. The request does not apply a URL-format rule.                                                                                               |
| `thanks_message`           | Nullable string at HTTP validation. For non-link actions, the stored schema requires a string when supplied. Used to seed the post-conversion message when the redirect flow has no children. |
| `platform`                 | Provider-name string.                                                                                                                                                                         |
| `form_ids`, `tag_ids`      | Arrays of strings.                                                                                                                                                                            |
| `list_id`, `automation_id` | Strings.                                                                                                                                                                                      |
| `event_name`               | Nonblank string. Trimmed and saved as one event name, not as a JSON list.                                                                                                                     |
| `redirect_url`             | String, maximum 2,000. Creates a root flow with one same-window redirect.                                                                                                                     |
| `redirectFunnel`           | Flow-definition object. Overrides `redirect_url` when both are supplied. Its nodes follow the [flow definition schema](https://rightmessage.com/help/rest-api-flows).                         |

Saved configuration must also pass action-specific validation. Passing request validation does not guarantee that an incomplete provider action can be saved. Nested `parts` and `action.settings` updates merge their supplied keys. A supplied list replaces that list.

There is a current mapping mismatch for `list_id` and `automation_id`. The service stores singular `listId` and `automationId`, while visitor actions consume `listIds` and `automationIds`. A successful save using those arguments alone does not establish that a list subscription or automation will run.

Non-link actions receive a root redirect flow when missing. If its `child` list is empty, repair inserts a message using `thanks_message`, or `Thank you!` when empty. Updating `thanks_message` does not overwrite an existing redirect flow's content. A directly supplied `redirectFunnel` does not receive the flow API's node normalization: include required node fields, such as `open` on redirect nodes.

For tag actions, repair trims `tag_ids`, splits entries at commas and newlines, and drops empty entries. For list actions, it normalizes the stored plural `listIds`, not the singular value produced by `list_id`. Unknown settings do not pass through unchanged. Only recognized settings are saved, so sending `listIds` directly is not a workaround through this endpoint.

## Offer responses and classification limits

The resource contains `id`, `name`, `is_enabled`, `parts`, and `action`. `parts` returns `title`, `description`, `button_text`, and `image_url`. `action` returns `type` plus `settings` containing only `url`, `thanks_message`, `platform`, and `tag_ids`. Missing settings appear as null.

The serializer does not echo `form_ids`, `list_id`, `automation_id`, `event_name`, or redirects. Their absence from a response is not evidence that the server discarded them.

There is a production classification mismatch. The offers list includes link actions only. Item GET, update, and delete reject only the exact action type `form`. A non-link action created here can therefore disappear from the offers list while remaining accessible by its offer ID. Keep the ID returned by create. The [forms API](https://rightmessage.com/help/rest-api-forms) describes the corresponding list behavior.

Deleting an offer clears its `offerId` from matching offer nodes in flows. The flow node remains in the draft.

## Illustrative requests and responses

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

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

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

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

{
	"name": "WorkForge demo",
	"parts": {
		"title": "See WorkForge",
		"button_text": "View demo"
	},
	"action": {
		"type": "link",
		"settings": {
			"url": "https://example.com/demo"
		}
	}
}

PATCH /v1/123456/offers/ofr_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/offers/ofr_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. The list places these resource objects in its `data` array. An update returns the updated values. DELETE returns no JSON.

```json
{
	"data": {
		"id": "ofr_example1",
		"name": "WorkForge demo",
		"is_enabled": true,
		"parts": {
			"title": "See WorkForge",
			"description": null,
			"button_text": "View demo",
			"image_url": null
		},
		"action": {
			"type": "link",
			"settings": {
				"url": "https://example.com/demo",
				"thanks_message": null,
				"platform": null,
				"tag_ids": null
			}
		}
	}
}
```
