REST API Reference
All NotedWP REST API endpoints live under the noted/v1 namespace. The base URL is:
https://yoursite.com/wp-json/noted/v1/
Authentication
NotedWP supports two authentication methods:
Logged-in WordPress users authenticate with the standard X-WP-Nonce header. Generate the nonce value from wp_create_nonce('wp_rest'). This is handled automatically if you use wp.apiFetch in JavaScript.
Guest reviewers authenticate with the X-Noted-Guest-Token header. Obtain a token by calling the guest registration endpoint. Guest tokens respect share link expiration and status.
Capabilities
Endpoints require one of these custom capabilities:
| Capability | Granted To | Description |
|---|---|---|
noted_manage_reviews |
Administrator | Full CRUD on pins, annotations, text edits |
noted_view_reviews |
Administrator, Editor | Read access to all review data |
noted_resolve_pins |
Administrator, Editor | Resolve and reopen pins |
noted_export_reviews |
Administrator | Export pins to external destinations |
Endpoints marked “guest” also accept a valid guest token in place of a WordPress capability.
Error Format
All errors follow the standard WP REST API format:
{
"code": "rest_forbidden",
"message": "Sorry, you are not allowed to do that.",
"data": { "status": 403 }
}
Common error codes:
| HTTP Status | Code | Meaning |
|---|---|---|
| 400 | rest_missing_callback_param |
A required parameter is missing |
| 401 | rest_not_logged_in |
No authentication provided |
| 403 | rest_forbidden |
Authenticated but lacking the required capability |
| 404 | rest_no_route |
Endpoint does not exist |
| 404 | noted_not_found |
Requested resource not found |
| 429 | noted_limit_reached |
Free tier limit reached (pins or guests) |
Pages
Ensure Page
Create a page record if it does not already exist. Returns the existing record if the URL path is already tracked.
| Method | POST |
| Path | /noted/v1/pages/ensure |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
project_id |
integer | Yes | ID of the internal default project. The overlay sends this automatically; you do not need to look it up. |
url_path |
string | Yes | Relative URL path (e.g., /about/). |
title |
string | No | Human-readable page title. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/pages/ensure"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"project_id": 1, "url_path": "/about/", "title": "About Us"}'
Example Response
{
"id": 12,
"project_id": 1,
"url_path": "/about/",
"title": "About Us",
"sort_order": 0,
"created_at": "2026-03-30T09:15:00"
}
Pins
List Pins
Retrieve pins, optionally filtered by page, status, breakpoint, or label.
| Method | GET |
| Path | /noted/v1/pins |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | No | Filter by page. |
project_id |
integer | No | References the internal default project. The overlay sends this automatically. |
status |
string | No | open or resolved. |
breakpoint |
string | No | desktop, tablet, or mobile. |
label |
string | No | Filter by label value. |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/pins?page_id=12&status=open"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{
"id": 42,
"page_id": 12,
"project_id": 1,
"x_percent": 45.2,
"y_percent": 30.8,
"css_selector": ".hero-title",
"selector_offset_x": 12.5,
"selector_offset_y": 8.3,
"viewport_width": 1440,
"scroll_y": 0,
"breakpoint": "desktop",
"pin_number": 7,
"status": "open",
"priority": "high",
"label": "design",
"is_internal": false,
"author_type": "user",
"author_user_id": 1,
"author_guest_id": null,
"body": "This heading should be larger.",
"attachment_ids": null,
"resolved_at": null,
"resolved_by": null,
"created_at": "2026-03-28T16:30:00",
"updated_at": "2026-03-28T16:30:00"
}
]
Create Pin
Place a new feedback pin on a page.
| Method | POST |
| Path | /noted/v1/pins |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | ID of the page to pin on. |
project_id |
integer | Yes | ID of the internal default project. The overlay sends this automatically. |
x_percent |
float | Yes | Horizontal position as a percentage (0-100). |
y_percent |
float | Yes | Vertical position as a percentage (0-100). |
css_selector |
string | No | CSS selector of the target element. |
selector_offset_x |
float | No | Horizontal offset within the selected element. |
selector_offset_y |
float | No | Vertical offset within the selected element. |
viewport_width |
integer | No | Viewport width at time of pin placement. |
scroll_y |
float | No | Scroll position at time of placement. |
breakpoint |
string | No | desktop (default), tablet, or mobile. |
priority |
string | No | normal (default), low, high, or critical. |
label |
string | No | Custom label (e.g., design, copy, bug). |
is_internal |
boolean | No | If true, pin is only visible to logged-in users. |
body |
string | No | Initial comment text for the pin. |
attachment_ids |
array | No | Array of WordPress media attachment IDs. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/pins"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{
"page_id": 12,
"project_id": 1,
"x_percent": 45.2,
"y_percent": 30.8,
"css_selector": ".hero-title",
"viewport_width": 1440,
"breakpoint": "desktop",
"priority": "high",
"body": "This heading should be larger."
}'
Example Response
{
"id": 42,
"page_id": 12,
"project_id": 1,
"x_percent": 45.2,
"y_percent": 30.8,
"pin_number": 7,
"status": "open",
"priority": "high",
"breakpoint": "desktop",
"body": "This heading should be larger.",
"created_at": "2026-03-30T10:00:00",
"updated_at": "2026-03-30T10:00:00"
}
Notes. On the free tier, pin creation is capped at 25 total pins. If the limit is reached the endpoint returns HTTP 429 with code noted_limit_reached. The pin_number is auto-assigned and increments sequentially. The noted_pin_created action fires after successful creation.
Update Pin
Update a pin’s status, body, label, priority, or internal flag.
| Method | PATCH |
| Path | /noted/v1/pins/{id} |
| Permission | noted_resolve_pins or pin author |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | Pin ID (URL path parameter). |
status |
string | No | open or resolved. |
body |
string | No | Updated comment body. |
label |
string | No | Updated label. |
priority |
string | No | Updated priority. |
is_internal |
boolean | No | Updated internal flag. |
Example Request
curl -X PATCH "https://yoursite.com/wp-json/noted/v1/pins/42"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"status": "resolved"}'
Example Response
Returns the updated pin object. When status changes to resolved, the resolved_at and resolved_by fields are populated and the noted_pin_resolved action fires.
Delete Pin
Permanently delete a pin and all its comments.
| Method | DELETE |
| Path | /noted/v1/pins/{id} |
| Permission | noted_manage_reviews |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | Pin ID (URL path parameter). |
Example Request
curl -X DELETE "https://yoursite.com/wp-json/noted/v1/pins/42"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
{
"deleted": true,
"id": 42
}
Bulk Resolve Pins
Resolve multiple pins at once.
| Method | POST |
| Path | /noted/v1/pins/bulk-resolve |
| Permission | noted_resolve_pins |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
ids |
array of integers | Yes | Pin IDs to resolve. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/pins/bulk-resolve"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"ids": [42, 43, 44]}'
Example Response
{
"resolved": [42, 43, 44],
"count": 3
}
Comments
List Comments
Retrieve all comments for a specific pin.
| Method | GET |
| Path | /noted/v1/pins/{pin_id}/comments |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
pin_id |
integer | Yes | Pin ID (URL path parameter). |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/pins/42/comments"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{
"id": 101,
"pin_id": 42,
"parent_id": null,
"author_type": "user",
"author_user_id": 1,
"author_guest_id": null,
"body": "Agreed, bumping this to 48px.",
"attachment_ids": null,
"created_at": "2026-03-28T17:00:00",
"updated_at": "2026-03-28T17:00:00"
}
]
Create Comment
Add a comment (or threaded reply) to a pin.
| Method | POST |
| Path | /noted/v1/pins/{pin_id}/comments |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
pin_id |
integer | Yes | Pin ID (URL path parameter). |
parent_id |
integer | No | ID of the parent comment for threaded replies. |
body |
string | No | Comment text. |
attachment_ids |
array | No | Array of WordPress media attachment IDs. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/pins/42/comments"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"body": "Fixed in the latest deploy.", "parent_id": 101}'
Example Response
{
"id": 102,
"pin_id": 42,
"parent_id": 101,
"author_type": "user",
"author_user_id": 1,
"author_guest_id": null,
"body": "Fixed in the latest deploy.",
"attachment_ids": null,
"created_at": "2026-03-30T11:00:00",
"updated_at": "2026-03-30T11:00:00"
}
Notes. The noted_comment_created action fires after successful creation.
Annotations
List Annotations
Retrieve all annotations for a page.
| Method | GET |
| Path | /noted/v1/annotations |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | Filter by page ID. |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/annotations?page_id=12"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{
"id": 8,
"page_id": 12,
"pin_id": 42,
"annotation_type": "rectangle",
"breakpoint": "desktop",
"data": "{"x":100,"y":200,"width":300,"height":150}",
"color": "#E06042",
"viewport_width": 1440,
"author_type": "user",
"author_user_id": 1,
"author_guest_id": null,
"created_at": "2026-03-28T16:35:00"
}
]
Create Annotation
Draw a rectangle, arrow, or freehand annotation on a page.
| Method | POST |
| Path | /noted/v1/annotations |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | ID of the page. |
annotation_type |
string | Yes | One of: rectangle, arrow, freehand. |
pin_id |
integer | No | Link the annotation to a specific pin. |
breakpoint |
string | No | desktop, tablet, or mobile. |
data |
string | No | JSON string containing annotation coordinates and dimensions. |
color |
string | No | Hex color (default: #E06042). |
viewport_width |
integer | No | Viewport width at time of drawing. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/annotations"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{
"page_id": 12,
"annotation_type": "rectangle",
"pin_id": 42,
"data": "{"x":100,"y":200,"width":300,"height":150}",
"color": "#FF0000"
}'
Example Response
Returns the created annotation object.
Delete Annotation
Delete an annotation. Only the author or a user with noted_manage_reviews can delete.
| Method | DELETE |
| Path | /noted/v1/annotations/{id} |
| Permission | noted_manage_reviews or annotation author |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | Annotation ID (URL path parameter). |
Example Request
curl -X DELETE "https://yoursite.com/wp-json/noted/v1/annotations/8"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
{
"deleted": true,
"id": 8
}
Text Edits
List Text Edits
Retrieve all text edit suggestions for a page.
| Method | GET |
| Path | /noted/v1/text-edits |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | Filter by page ID. |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/text-edits?page_id=12"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{
"id": 3,
"page_id": 12,
"pin_id": null,
"css_selector": ".hero-subtitle",
"original_text": "We build greate websites.",
"suggested_text": "We build great websites.",
"breakpoint": "desktop",
"status": "pending",
"author_type": "guest",
"author_user_id": null,
"author_guest_id": 7,
"created_at": "2026-03-29T10:00:00",
"updated_at": "2026-03-29T10:00:00"
}
]
Create Text Edit
Suggest a text change on a page element.
| Method | POST |
| Path | /noted/v1/text-edits |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | ID of the page. |
css_selector |
string | Yes | CSS selector of the element containing the text. |
original_text |
string | Yes | The current text content. |
suggested_text |
string | Yes | The proposed replacement text. |
pin_id |
integer | No | Link the text edit to a specific pin. |
breakpoint |
string | No | desktop, tablet, or mobile. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/text-edits"
-H "X-Noted-Guest-Token: GUEST_TOKEN_HERE"
-H "Content-Type: application/json"
-d '{
"page_id": 12,
"css_selector": ".hero-subtitle",
"original_text": "We build greate websites.",
"suggested_text": "We build great websites."
}'
Example Response
Returns the created text edit object.
Update Text Edit Status
Accept or reject a text edit suggestion.
| Method | PATCH |
| Path | /noted/v1/text-edits/{id} |
| Permission | noted_manage_reviews |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
integer | Yes | Text edit ID (URL path parameter). |
status |
string | Yes | One of: pending, accepted, rejected. |
Example Request
curl -X PATCH "https://yoursite.com/wp-json/noted/v1/text-edits/3"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"status": "accepted"}'
Example Response
Returns the updated text edit object.
Guests
Register Guest
Register a new guest reviewer for the review site. This endpoint is public (no authentication required), but requires a valid share token.
| Method | POST |
| Path | /noted/v1/guests/register |
| Permission | Public |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
project_token |
string | Yes | The access_token from the share link. |
name |
string | Yes | Guest’s display name. |
email |
string | No | Guest’s email address. |
password |
string | No | Required if the review site is password-protected. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/guests/register"
-H "Content-Type: application/json"
-d '{
"project_token": "a1b2c3d4e5f6...",
"name": "Sarah Client",
"email": "[email protected]"
}'
Example Response
{
"guest_id": 7,
"token": "x9y8z7w6v5u4...",
"name": "Sarah Client",
"project_id": 1
}
Notes. On the free tier, guest registration is capped at 3 guests per review site. The returned token value should be stored client-side and sent as the X-Noted-Guest-Token header on subsequent requests.
Validate Guest Token
Check whether a guest token is still valid.
| Method | POST |
| Path | /noted/v1/guests/validate |
| Permission | Public |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
token |
string | Yes | The guest token to validate. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/guests/validate"
-H "Content-Type: application/json"
-d '{"token": "x9y8z7w6v5u4..."}'
Example Response
{
"valid": true,
"guest_id": 7,
"name": "Sarah Client",
"email": "[email protected]"
}
Check Access
Check whether the review site requires a password before showing the registration form.
| Method | POST |
| Path | /noted/v1/guests/check-access |
| Permission | Public |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
project_token |
string | Yes | The access_token from the share link. |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/guests/check-access"
-H "Content-Type: application/json"
-d '{"project_token": "a1b2c3d4e5f6..."}'
Example Response
{
"requires_password": false,
"site_name": "Homepage Redesign"
}
Export
Export Pins
Export selected pins to an external destination (CSV, Trello, Asana, Jira, Linear, GitHub, Monday, Slack, Webhook, or M13 Dashboard).
| Method | POST |
| Path | /noted/v1/export |
| Permission | noted_export_reviews |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
pin_ids |
array of integers | Yes | IDs of pins to export. |
destination |
string | Yes | Export destination identifier (e.g., csv, trello, slack). |
options |
object | No | Destination-specific options (board ID, channel, etc.). |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/export"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{
"pin_ids": [42, 43],
"destination": "csv",
"options": {}
}'
Example Response
{
"success": true,
"export_id": 15,
"destination": "csv",
"destination_ref": "https://yoursite.com/wp-content/uploads/noted-exports/export-15.csv"
}
List Export Destinations
Retrieve available export destinations and their configuration status.
| Method | GET |
| Path | /noted/v1/export/destinations |
| Permission | noted_export_reviews |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/export/destinations"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{ "id": "csv", "name": "CSV", "configured": true, "requires_plan": "free" },
{ "id": "trello", "name": "Trello", "configured": true, "requires_plan": "pro" },
{ "id": "slack", "name": "Slack", "configured": false, "requires_plan": "pro" },
{ "id": "webhook", "name": "Webhook", "configured": true, "requires_plan": "agency" }
]
Admin
Force License Revalidation
Force the plugin to re-check the license status with the update server.
| Method | POST |
| Path | /noted/v1/admin/force-revalidate |
| Permission | noted_manage_reviews |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/admin/force-revalidate"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
{
"plan": "pro",
"revalidated": true
}
Get Sitemap
Retrieve a list of all public pages on the site (used by the page picker in the admin).
| Method | GET |
| Path | /noted/v1/sitemap |
| Permission | noted_manage_reviews |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/sitemap"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{ "url": "/", "title": "Home" },
{ "url": "/about/", "title": "About Us" },
{ "url": "/contact/", "title": "Contact" }
]
Get Stats
Retrieve aggregate statistics for the dashboard.
| Method | GET |
| Path | /noted/v1/stats |
| Permission | noted_view_reviews |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/stats"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
{
"open_pins": 12,
"resolved_pins": 34,
"total_pins": 46,
"pages_reviewed": 8
}
Presence
Heartbeat
Send a presence heartbeat to indicate the current user is actively viewing a page. Call this periodically (every 15-30 seconds) to keep the user visible in the active users list.
| Method | POST |
| Path | /noted/v1/presence |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | ID of the page being viewed. |
name |
string | No | Display name (useful for guests). |
Example Request
curl -X POST "https://yoursite.com/wp-json/noted/v1/presence"
-H "X-WP-Nonce: YOUR_NONCE"
-H "Content-Type: application/json"
-d '{"page_id": 12}'
Example Response
{
"success": true
}
Get Active Users
Retrieve the list of users currently viewing a specific page.
| Method | GET |
| Path | /noted/v1/presence |
| Permission | noted_view_reviews or guest token |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
page_id |
integer | Yes | ID of the page. |
Example Request
curl -X GET "https://yoursite.com/wp-json/noted/v1/presence?page_id=12"
-H "X-WP-Nonce: YOUR_NONCE"
Example Response
[
{ "name": "Admin", "type": "user", "user_id": 1 },
{ "name": "Sarah Client", "type": "guest", "guest_id": 7 }
]