Skip to help content
RightMessage

Hosted page and template API reference

Manage hosted-page content, publication, SEO settings, and media, and read the public template catalog.

Available on the Scale and Pro plans.

Updated

View as Markdown

These endpoints manage hosted pages and their supporting assets. They are dashboard API routes under /api, not public REST v1 resources. Page publication is separate from publishing the project's snippet configuration.

Authentication, paths, and rate limits

Project routes use https://api.rightmessage.com/api/{teamPid}. They require an authenticated session or API token, project membership or administrator access, and account and project suspension checks. Browser-session writes require CSRF protection. Bearer tokens are accepted, but these routes do not enforce v1 read, write, or publish abilities.

Template catalog routes use https://api.rightmessage.com/api/template-catalog and do not require authentication. Neither the page/media route group nor the catalog declares a numeric per-route throttle. Do not apply v1's 120-per-minute declaration to them. Global infrastructure limits can still apply.

Send Accept: application/json and JSON bodies with Content-Type: application/json. The illustrative requests below use bearer placeholders for clarity and were not executed.

Page operations

A pid is the encoded numeric-string page identifier returned by the API, not its slug or database ID. Item routes require digits. The project scopes every lookup.

Method and pathBody or querySuccess
GET /pagesOptional status, type, and search query strings200, bare array of page resources
POST /pagesCreate fields below201, bare page resource
GET /pages/{pid}None200, bare page resource
PUT /pages/{pid}Update fields below200, bare page resource
DELETE /pages/{pid}None204, empty body
POST /pages/{pid}/publishNone200, bare page resource
POST /pages/{pid}/unpublishNone200, bare page resource
POST /pages/{pid}/duplicateOptional name201, bare new page resource
POST /pages/{pid}/archiveNone200, bare page resource

Page resources are not wrapped in data. This differs from public v1 resource serializers. There is no PATCH page route.

The list orders newest first and has no pagination. Status and type are exact filters without request validation. Search uses SQL LIKE matching on name or slug. Duplicate accepts an unvalidated name, defaulting to the original name plus (Copy). It copies content, settings, flow, and metadata, and creates a draft with a unique slug. A slug collision on duplication falls back to a random slug.

Page create and update fields

FieldCreateUpdate
nameRequired string, maximum 255Optional string, maximum 255
typeRequired: lead_gen or quiz_funnelOptional, same values
slugNullable string, maximum 255; generated when emptyOptional non-null string, maximum 255
statusNullable: draft, published, archived; defaults draftOptional non-null value from the same set
contentNullable objectOptional nullable object
settingsNullable objectOptional nullable object

Slugs must match ^[a-z0-9]+(?:-[a-z0-9]+)*$ and be unique within the project. Duplicate slugs return 422. A new page also creates the project's hosted-page slug if one is missing.

Both create and update declare these nullable content fields:

KeysType and limit
flowIdString, maximum 255. No existence check in the request.
templatecentered or split
logo, headline, authorSignatureStrings, maximum 500
descriptionString, maximum 2,000
backgroundColor, accentColorStrings, maximum 50

Update additionally declares these nullable content fields:

KeysType and limit
containerBackgroundColor, borderColor, textColorStrings, maximum 50
borderRadius, borderWidth, buttonBorderRadius, answerButtonSpacing, formFieldSpacingStrings, maximum 20
flowHeadlineFontSize, flowDescriptionFontSize, answerButtonFontSize, formFieldFontSize, submitButtonFontSize, headlineFontSize, descriptionFontSizeStrings, maximum 20
containerShadowBoolean
fontString, maximum 100
lineHeightNumber, 1 through 3
customCssString, maximum 10,000

The parent objects are not closed key allowlists. The tables describe fields with explicit validation, not a guarantee that unknown nested keys are rejected. Supplied content and settings replace their stored objects rather than merging nested values.

SEO settings available through the API

Both requests accept nullable settings.metaTitle, string up to 255; settings.metaDescription, string up to 1,000; and settings.ogImage and settings.favicon, strings up to 500. These fields are API-accessible even when a dashboard editor does not expose a control.

Use those nested settings for SEO. The response also includes legacy top-level meta_title, meta_description, og_image, favicon, and flow_id columns. The request validators do not declare those top-level write fields. The page renderer uses content.flowId for the flow, and the page's meta-title helper uses settings.metaTitle with the page name as fallback.

Page response and immediate effects

Each page resource contains pid, slug, name, type, status, content, settings, the legacy columns above, views_count, conversions_count, percentage conversion_rate, full_url, nullable published_at, nullable last_published_at, created_at, updated_at, and booleans is_published, is_draft, is_archived, is_lead_gen, and is_quiz_funnel.

Item and lifecycle responses also include team with pid, name, slug, and pages_base_url. Other responses include it when project details are loaded. The URL uses the project slug, configured pages domain, and page slug. Conversion rate is conversions divided by views times 100, rounded to two decimals, or zero with no views.

Publish changes status to published, initializes published_at if absent, and updates last_published_at. Unpublish changes status to draft; archive changes it to archived. Both retain publication timestamps. Only published, non-deleted pages on nonsuspended projects render publicly.

There is no second page-content draft hidden behind a published page. Updating a published page changes its stored live content directly. Supplying status: "published" on create or update changes visibility without calling the publish method, so it does not have that method's timestamp behavior. The embedded flow is extracted from stable project configuration, not the current flow draft.

Page publishing does not validate that content.flowId exists or has usable dependencies. Hosted pages include questions referenced through segment-group IDs. Direct raq_ question references, including input questions with no group, are not included in that question list. A successful page publish is not proof that such a flow will render correctly. Check the public page before sharing it.

Illustrative page requests and shared response

These operations use the fictional WorkForge project. The same page resource contract covers list, create, read, update, publish, unpublish, duplicate, and archive. Status fields reflect the requested lifecycle operation. The duplicate response has a new pid and draft status.

HTTP
GET /api/123456/pages?status=draft&type=lead_gen&search=WorkForge HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

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

{"name":"WorkForge demo","type":"lead_gen","slug":"workforge-demo","content":{"template":"centered","headline":"See WorkForge","logo":"https://example.com/logo.png"}}

GET /api/123456/pages/987654 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

PUT /api/123456/pages/987654 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Content-Type: application/json

{"settings":{"metaTitle":"WorkForge demo","metaDescription":"See how WorkForge helps your team."}}

POST /api/123456/pages/987654/publish HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

POST /api/123456/pages/987654/unpublish HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

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

{"name":"WorkForge demo copy"}

POST /api/123456/pages/987654/archive HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

DELETE /api/123456/pages/987654 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Illustrative page-resource excerpt. The list returns an array of these objects; DELETE returns no body. The field list above defines the full resource.

JSON
{"pid":"987654","slug":"workforge-demo","name":"WorkForge demo","type":"lead_gen","status":"draft","content":{"template":"centered","headline":"See WorkForge","logo":"https://example.com/logo.png"},"settings":{"metaTitle":"WorkForge demo"},"views_count":0,"conversions_count":0,"conversion_rate":0,"published_at":null,"last_published_at":null,"is_published":false,"is_draft":true,"is_archived":false}

Project media operations

These routes share the page authentication boundary and affect storage immediately, without publishing.

Method and pathRequestSuccess
GET /filesNo parameters200, bare array of filenames
POST /filesMultipart file, required file, maximum 2,048 KiB; jpeg, jpg, png, gif, or svg200, filename string, not a JSON resource envelope
DELETE /files/{hash}Filename from storage, no body200, {"message":"File deleted successfully"}
POST /files/from-urlJSON url, required valid URL, maximum 2,048 characters200, {"hashName":"..."}

URL import downloads the image with a 30-second timeout. Allowed response media types are image/jpeg, image/png, image/gif, image/svg+xml, and image/webp. Content must not exceed 2,097,152 bytes. WebP is accepted by URL import but not by the multipart validator.

Imported filenames use the content MD5 plus a normalized extension. Existing identical content at that project path returns existing: true with hashName. New uploads omit existing. Import stores the file, not a page reference. A hosted page logo can use usf://FILENAME, which the page renderer resolves to the project's media URL.

Deduplication is by content hash plus extension, not content alone. Identical bytes imported with different accepted extensions can create separate files. Deleting media does not inspect or rewrite page references, and a missing filename still receives the same success message. Remove references before deleting an image that a published page uses.

Illustrative calls, not executed:

Bash
curl 'https://api.rightmessage.com/api/123456/files' -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'Accept: application/json'
curl 'https://api.rightmessage.com/api/123456/files' -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'Accept: application/json' -F 'file=@workforge-logo.png'
curl -X POST 'https://api.rightmessage.com/api/123456/files/from-url' -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'Accept: application/json' -H 'Content-Type: application/json' --data '{"url":"https://example.com/logo.png"}'
curl -X DELETE 'https://api.rightmessage.com/api/123456/files/0123456789abcdef0123456789abcdef.png' -H 'Authorization: Bearer YOUR_API_TOKEN' -H 'Accept: application/json'

Corresponding illustrative bodies, in request order:

Text
["0123456789abcdef0123456789abcdef.png"]
workforge-upload-hash.png
{"hashName":"0123456789abcdef0123456789abcdef.png","existing":true}
{"message":"File deleted successfully"}

URL import returns 422 with error for Invalid image type. Allowed: jpeg, png, gif, svg, webp, Image too large (max 2MB), or Failed to download image from URL. Request validation instead returns the normal message and errors envelope. Other storage or network failures can return 500.

Public template catalog

The catalog describes available templates without installing them or changing a project.

GET /api/template-catalog returns 200 with data, an array of entries, and meta: {last_page:1}. It returns the entire catalog, ordered by configured order then title. There are no supported query filters or pagination inputs.

GET /api/template-catalog/{idOrSlug} accepts an exact template UUID or filename-derived slug. It returns 200 with data, one entry, or 404 when absent. Neither endpoint installs a template or changes a project.

Each entry contains id, slug, title, nullable description, nullable preview_image with a url, template_type: {value:string}, boolean hide_preview, nullable impact_statement, nullable best_for, array template_categories, nullable structural_archetype, boolean is_skeleton, and payload_json: {value:string}. The payload value is serialized JSON text, not an already-decoded object. Template type defaults flow; boolean flags default false.

Illustrative requests and response excerpts, not executed. The slug and entry are fictional:

HTTP
GET /api/template-catalog HTTP/1.1
Host: api.rightmessage.com
Accept: application/json

GET /api/template-catalog/workforge-welcome HTTP/1.1
Host: api.rightmessage.com
Accept: application/json
JSON
{"data":[{"id":"11111111-1111-4111-8111-111111111111","slug":"workforge-welcome","title":"WorkForge welcome","template_type":{"value":"flow"},"payload_json":{"value":"{}"}}],"meta":{"last_page":1}}

The item response uses {"data":ENTRY} with the same full entry schema. The abbreviated example payload is not an installable template.

Common failures

Authenticated routes return 401 for missing authentication and 403 for denied access or suspension. Invalid page or media inputs return 422. Missing, deleted, wrong-project, or nondigit page IDs return 404. Browser-session writes can fail CSRF protection. Maintenance returns 503 for these API routes, including the otherwise-public catalog. These operations do not create v1 configuration drafts or snapshots, or send v1 draft-update notifications.

Still need a hand?

Tell us what you’re trying to do and where you’re getting stuck.

support@rightmessage.com