# REST API authentication and request conventions

Reference for REST authentication, project identifiers, abilities, response envelopes, limits, errors, and drafts.

Available on the Scale and Pro plans.

The public REST API reads project configuration and analytics, saves configuration drafts, starts exports, and publishes a project. It is distinct from the dashboard's session API and the hosted MCP connection.

## Base URL and authentication

The base URL is `https://api.rightmessage.com/v1`. Authenticate with an API token in `Authorization: Bearer YOUR_API_TOKEN`. Send `Accept: application/json`; JSON bodies also use `Content-Type: application/json`.

The [API token setup guide](https://rightmessage.com/help/api-tokens-and-permissions) explains how to create your first token in the dashboard.

Project endpoints use `/{teamPid}/...`. This is the public project identifier, not its name or an internal database ID. Resource IDs come from responses and are scoped to the chosen project's configuration. Use the returned strings unchanged.

A token belongs to a user, not one project. Project members and administrators can access project routes. Ordinary API mutations do not require the owner role. Nonmembers receive 403. An unknown project receives 404.

Token creation requires API access on the account. Project endpoints do not repeat that token-creation entitlement check. Subscription and publication requirements remain separate from token abilities. See [token creation and its plan requirement](https://rightmessage.com/help/rest-api-access#post-tokens).

## Illustrative authenticated request

This illustrative request reads flows from the fictional WorkForge project.

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

```json
{"data":[{"id":"ofn_example1","name":"WorkForge welcome","definition":{"type":"root","child":[]}}]}
```

## Abilities and their limits

| Ability   | Project-route access                                                          |
| --------- | ----------------------------------------------------------------------------- |
| `read`    | Configuration, analytics, data, and export status/download GET routes         |
| `write`   | Those GET routes plus configuration create/update/delete and starting exports |
| `publish` | The publish operation; it does not by itself grant the GET or CRUD routes     |
| `*`       | All ability checks                                                            |

Read routes accept either `read` or `write`. Omitted abilities on token creation default to `["*"]`. An explicitly empty abilities array remains empty.

These abilities are not a comprehensive security sandbox. The user-scoped `/tokens` and `/oauth-connections` routes require authentication but have no ability middleware. A read-only token can therefore reach token management, including creation when the account gate permits it. Tokens are not project-restricted. The hosted MCP route does not apply the public REST ability checks either. Do not distribute a token on the assumption that `read` prevents every write outside project v1 routes.

[Tokens and OAuth connections](https://rightmessage.com/help/rest-api-access) documents the exact management operations.

## Rate limits

User-scoped token and OAuth management routes allow 60 requests per minute. Project routes allow 120 requests per minute. These are route limits, not independent quotas for every resource or token. Excess requests return 429. The response exposes remaining-limit information and a retry interval when throttled.

These limits do not apply by inheritance to the separate `/api` hosted-page and template routes. See [hosted page and template API](https://rightmessage.com/help/hosted-page-api).

## JSON and validation

Request names are case-sensitive. Most v1 resource fields use snake\_case, while flow definitions and nested design/input settings retain documented camelCase names.

Optional means a field can be omitted. Nullable means request validation accepts an explicit JSON null, though stored-configuration validation may still reject it. Boolean request fields accept booleans, 0, 1, `"0"`, and `"1"` without converting their types. Use JSON booleans and numbers for stored boolean and numeric fields. A field described as `array` can represent an object or a list. Follow the documented shape.

Undocumented top-level fields are not part of the write contract. Some nested objects accept additional keys, but mapping and full-configuration validation determine whether those keys survive. An accepted request shape does not guarantee a valid flow, campaign, or widget configuration.

## Success envelopes

| Operation                       | Typical contract                                                                   |
| ------------------------------- | ---------------------------------------------------------------------------------- |
| List a configuration resource   | 200, `{"data":[RESOURCE]}`; no pagination                                          |
| Read or update one resource     | 200, `{"data":RESOURCE}`                                                           |
| Create a configuration resource | 201, `{"data":RESOURCE}`                                                           |
| Delete a configuration resource | 204, no body                                                                       |
| Start an export                 | 202, `{"data":{"job_id":"...","status":"processing","message":"Export started."}}` |
| Read analytics or project data  | 200, `{"data":...}`; payload differs by endpoint                                   |
| Publish                         | 200, top-level `message` and `published_at`, without a data envelope               |

Do not assume every response has `data`. Errors, publication responses, and dashboard media endpoints use other shapes.

## Error contract

| Status | Meaning and body                                                                                                                                                                              |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | Authentication failed. JSON requests receive a `message`.                                                                                                                                     |
| 403    | Membership, ability, entitlement, or suspension check failed. Usually `message`. Project suspension adds `code: "project_suspended"`; account suspension adds `code: "account_suspended"`.    |
| 404    | Project or item not found, or not owned by the requested scope. Usually `message`; exports have endpoint-specific bodies.                                                                     |
| 409    | Endpoint-specific conflict: publication activation is busy, or an export is not complete. See each endpoint's body shape.                                                                     |
| 422    | Request validation failure with `message` and `errors`, a map of field paths to message arrays. Active question-test locks can use `errors.config`. Publish-without-draft has only `message`. |
| 429    | Route rate limit exceeded.                                                                                                                                                                    |
| 500    | Unhandled service failure. Full-configuration schema failures can reach this status rather than 422. Do not depend on debug exception details being exposed.                                  |
| 503    | Maintenance or reporting unavailable. Maintenance returns `error: "maintenance"`, `message`, and nullable `estimatedEnd`. Reporting errors differ by endpoint.                                |

Authenticated users can send GET requests to the demo project. Demo mutations return 403. A request from a suspended account invalidates its presented API token and session.

Illustrative validation response:

```json
{
	"message": "The name field is required.",
	"errors": {"name": ["The name field is required."]}
}
```

## Draft and live configuration

Configuration CRUD reads the draft first, then stable configuration. Mutations save a draft and a snapshot of the previous configuration, and notify open dashboards. They do not change the published snippet by themselves.

Saving includes configuration repair before schema validation. The saved response can therefore contain defaults absent from the request, including question Other labels, form fields, and widget design settings. Validation covers the whole configuration, not just the edited resource. A failed mutation can leave a snapshot or a newly created draft behind; an error is not a transaction-level promise that nothing changed.

Active question A/B tests protect wording, answers, display, behavior, and linked Auto-Segment rules at the configuration save boundary. Such a change can return 422 under `errors.config`, including through a segment-group update or deletion. Sync mappings, internal names, and flow membership remain editable. This is separate from the token's `write` ability.

A request to a project you belong to can switch your current project to the one in the URL. Account-level entitlement checks then use that project.

PUT and PATCH are both partial updates at the top level. Nested merge and replacement rules differ by resource. In particular, a campaign's supplied changes list and a flow's supplied definition can remove content omitted from the payload.

[Publishing](https://rightmessage.com/help/rest-api-publishing) applies the entire project draft, not just changes made by the current token. Analytics describe recorded activity, not draft previews. Project data endpoints have different draft and live sources. Hosted-page changes take effect separately and do not wait for v1 publication.
