Skip to main content

Pages

Page endpoints allow you to create, read, update, and delete pages within projects. Pages are the content that QR codes link to. Pages are a shallow resource under projects: you list and create pages in the context of a project (/projects/{project}/pages), but get, update, and delete a single page by its ID (/pages/{id}).

Enums (integer-backed):

  • visibility: 1 = public, 2 = hidden, 3 = private (password-protected)
  • template: 0 = default, 1 = link, 2 = vcard_plus, 3 = document, 4 = social

List Pages

Get a list of all pages in a project. Each item is a collection representation (no form_data, sections, or page_design_template). The response includes included_qr_codes: QR code resources for each page that has a linked QR code.

GET https://v1.freeqr.io/api/projects/{project}/pages

Requires Authentication: Yes

Path Parameters

ParameterTypeRequiredDescription
projectstring (ULID)YesProject ID

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 10, max: 100)
sortstringNoSort field: id, views, name (prefix with - for descending)
filters[search]stringNoSearch by page name (partial match)

Response

{
"data": [
{
"id": "01arz3ndektsv4rrffq69g5fav",
"project_id": "01arz3ndektsv4rrffq69g5fav",
"name": "My Page",
"domain": "example.com",
"handle": "my-page",
"visibility": 1,
"password": null,
"password_hint": null,
"template": 0,
"page_design_template_id": null,
"views": 150,
"form_submissions_count": 5,
"unseen_form_submissions_count": 2,
"created_at": "2024-01-01T00:00:00.000000Z",
"updated_at": "2024-01-01T00:00:00.000000Z"
}
],
"meta": {
"total": 1
},
"included_qr_codes": []
}

List items do not include form_data, sections, or page_design_template; use Get Page for full detail.

Create Page

Create a new page in a project.

POST https://v1.freeqr.io/api/projects/{project}/pages

Requires Authentication: Yes

Path Parameters

ParameterTypeRequiredDescription
projectstring (ULID)YesProject ID

Request Body

{
"name": "My New Page",
"domain": "example.com",
"handle": "my-new-page",
"template": 0,
"visibility": 1,
"password": null,
"password_hint": "Hint for password",
"page_design_template_id": "01arz3ndektsv4rrffq69g5fav",
"form_data": {}
}

Parameters

ParameterTypeRequiredDescription
namestringYesPage name (max 100 characters)
domainstringNoDomain (max 100, must exist in domains). If omitted, the first available domain is used.
handlestringNoPage handle/slug (max 60 characters). Stored slugified; must be unique per domain.
templateintegerNoPage template enum: 04 (see template enum above)
visibilityintegerNoVisibility enum: 1 public, 2 hidden, 3 private
passwordstringNoPassword for password-protected pages (min 1, max 100 when set)
password_hintstringNoPassword hint (max 255 characters)
page_design_template_idstring (ULID)NoPage design template ID (must be type PAGE_DESIGN). When provided, the template's current version config is merged with form_data; form_data overrides template config.
form_dataobjectNoForm data (max 200 keys). Validated against page form sections; overrides template config when page_design_template_id is set.

Possible errors:

  • 422 — Handle already taken: body message like Handle "my-page" is already taken. Please choose another one. (handle is slugified and checked for uniqueness per domain).
  • 403 — Max pages limit reached: body message Max pages limit reached. Please upgrade your plan.

Response

Returns the created page as a full PageResource (same shape as Get Page): includes form_data, sections, page_design_template (when loaded and viewable). No included_files on create.

{
"id": "01arz3ndektsv4rrffq69g5fav",
"project_id": "01arz3ndektsv4rrffq69g5fav",
"name": "My New Page",
"domain": "example.com",
"handle": "my-new-page",
"visibility": 1,
"password": null,
"password_hint": null,
"template": 0,
"page_design_template_id": null,
"views": 0,
"form_submissions_count": 0,
"unseen_form_submissions_count": 0,
"form_data": {},
"sections": [],
"page_design_template": null,
"created_at": "2024-01-01T00:00:00.000000Z",
"updated_at": "2024-01-01T00:00:00.000000Z"
}

When page_design_template_id is provided, the template's current version config is merged with form_data (with sanitization); form_data is then validated against the page's form sections.

Get Page

Get a single page by ID. Returns the full PageResource (including form_data, sections, page_design_template when loaded and viewable) plus included_files (files referenced by the page).

GET https://v1.freeqr.io/api/pages/{id}

Requires Authentication: Yes

Path Parameters

ParameterTypeRequiredDescription
idstring (ULID)YesPage ID

Response

{
"id": "01arz3ndektsv4rrffq69g5fav",
"project_id": "01arz3ndektsv4rrffq69g5fav",
"name": "My Page",
"domain": "example.com",
"handle": "my-page",
"visibility": 1,
"password": null,
"password_hint": null,
"template": 0,
"page_design_template_id": null,
"views": 150,
"form_submissions_count": 5,
"unseen_form_submissions_count": 2,
"form_data": {},
"sections": [],
"page_design_template": null,
"created_at": "2024-01-01T00:00:00.000000Z",
"updated_at": "2024-01-01T00:00:00.000000Z"
}

Top-level included_files is also returned (array of file resources referenced by this page). page_design_template is included only when the template relation is loaded and the authenticated user can view it.

Update Page

Update an existing page. Only the following fields are updatable; domain and handle cannot be changed.

PATCH https://v1.freeqr.io/api/pages/{id}

Requires Authentication: Yes

Path Parameters

ParameterTypeRequiredDescription
idstring (ULID)YesPage ID

Request Body

{
"name": "Updated Page Name",
"template": 0,
"visibility": 3,
"password": "new-password",
"password_hint": "Hint text",
"page_design_template_id": "01arz3ndektsv4rrffq69g5fav",
"form_data": {}
}

Parameters

ParameterTypeRequiredDescription
namestringNoPage name (max 100 characters)
templateintegerNoPage template enum: 04
visibilityintegerNoVisibility: 1 public, 2 hidden, 3 private
passwordstringNoPassword (required when visibility is 3; min 1, max 100)
password_hintstringNoPassword hint (max 255 characters)
page_design_template_idstring (ULID)NoPage design template ID (PAGE_DESIGN type). Template config is merged with form_data; form_data overrides.
form_dataobjectNoForm data (max 200 keys); validated and merged with template config when page_design_template_id is set.

Response

Same structure as Get Page (full PageResource; included_files not included on update response).

Delete Page

Delete a page.

DELETE https://v1.freeqr.io/api/pages/{id}

Requires Authentication: Yes

Path Parameters

ParameterTypeRequiredDescription
idstring (ULID)YesPage ID

Response

Returns the deleted page resource (same structure as Get Page).

Get Public Page

Get a public page by identifier. Used for unauthenticated access (e.g. when a user scans a QR code). The identifier is the page's handle and domain in the form handle.domain (e.g. my-page.example.com).

GET https://v1.freeqr.io/api/pages/public/{identifier}

Requires Authentication: No

Path Parameters

ParameterTypeRequiredDescription
identifierstringYesPage identifier: handle.domain (e.g. my-page.example.com)

Query Parameters

ParameterTypeRequiredDescription
tokenstringNoAccess token for password-protected pages (obtained from Unlock Page)

Response

Success (200): Returns the public page payload plus included_files and included_components. The main payload contains only id, domain, handle, and form_data. Components are filtered by public visibility.

{
"id": "01arz3ndektsv4rrffq69g5fav",
"domain": "example.com",
"handle": "my-page",
"form_data": {}
}

Top-level included_files (files for the page and its components) and included_components (public components) are also returned.

Password-protected without valid token (403): When the page is not public and no valid token is provided:

{
"meta": {
"page_id": "01arz3ndektsv4rrffq69g5fav",
"password_hint": "Hint for password"
}
}

Use Unlock Page with the page ID and password to obtain a token, then call this endpoint again with ?token=....

Unlock Page

Unlock a password-protected page and get a temporary access token. Use this when the user has entered the correct password; then call Get Public Page with ?token={token} to load the page.

POST https://v1.freeqr.io/api/pages/{page}:unlock

Requires Authentication: No

Path Parameters

ParameterTypeRequiredDescription
pagestring (ULID)YesPage ID

Request Body

{
"password": "page-password"
}

Parameters

ParameterTypeRequiredDescription
passwordstringYesPage password (max 255 characters)

Response

Success: Returns a temporary token in meta.token. Use it as the token query parameter when calling Get Public Page.

{
"meta": {
"token": "access-token-string"
}
}

Incorrect password: Response body contains "message": "Incorrect password."