REST API Reference
SnipShare exposes a complete REST API under the snipshare/v1 namespace. All endpoints are accessible at /wp-json/snipshare/v1/.
Authentication
Section titled “Authentication”| Method | Use Case |
|---|---|
| WP Cookie + X-WP-Nonce header | Logged-in users on the frontend. Get nonce via wp_rest_nonce() or wpApiSettings.nonce. |
| Application Passwords | External apps, mobile clients, CLI tools. Create at WP Admin → Users → Edit User → Application Passwords. |
Public endpoints (reading public pastes, tags, oEmbed) require no authentication.
Licence: Authenticated calls from apps and scripts (Application Passwords, Basic auth or a token plugin, that is, a logged-in request without a REST nonce) need the Developer licence or above; otherwise they return
403with the codesnipshare_license_required. Public reads by guests and the plugin’s own pages (which send a REST nonce) work on every tier. Revision routes need the Developer licence; moderation routes work on every tier.
Global Parameters
Section titled “Global Parameters”All list endpoints support these query parameters:
| Parameter | Description |
|---|---|
page |
Page number (default: 1) |
per_page |
Results per page (default: 20, max: 100) |
orderby |
Sort field (e.g., created_at, star_count, view_count) |
order |
asc or desc (default: desc) |
_fields |
Comma-separated list of fields to include in response (sparse fieldsets) |
_embed |
Include linked resources inline (author, files) |
Pagination response headers: X-WP-Total (total items), X-WP-TotalPages (total pages).
List endpoints load files, tags and authors for the whole page at once, so a page of 100 runs about the same number of database queries as a page of 10.
Pastes
Section titled “Pastes”List Pastes
Section titled “List Pastes”GET /wp-json/snipshare/v1/pastesReturns public pastes. Supports additional filter params:
| Param | Description |
|---|---|
language |
Filter by language slug |
user |
Filter by WP user ID or profile slug (the user_nicename used in profile URLs) |
tag |
Filter by tag slug |
search |
Search in title and description |
orderby |
created_at (default), updated_at, view_count, star_count, fork_count, or title |
order |
DESC (default) or ASC |
Burn-after-read pastes are never listed.
Create Paste
Section titled “Create Paste”POST /wp-json/snipshare/v1/pastesAuth required. Request body (JSON):
{ "title": "My helper", "description": "Useful PHP utility", "visibility": "public", "expires_in": "never", "password": "", "burn_after_read": false, "tags": ["php", "utilities"], "files": [ { "filename": "helper.php", "content": "<?php function foo() {}", "language": "php" } ]}tagsis a list of tag names. Responses return tags as objects (id,name,slug).expires_in:never,10m,1h,1d,1w,1M,3M,6M, or1y.- Every paste object includes
link, the URL of its page. Use it instead of building/paste/{hash}/yourself, so sites installed in a subfolder work.
Get Paste
Section titled “Get Paste”GET /wp-json/snipshare/v1/pastes/{id}Access rules:
- Public: anyone.
- Unlisted: send
?share_hash=<hash>, or be the author or a moderator. A numeric id alone returns 404. - Private: author and moderators only. Everyone else gets 404, not 403.
- Password-protected: until unlocked with
POST /pastes/{id}/unlock, the paste is returned withis_locked: trueand emptyfiles. Content endpoints (revisions, diff, raw, download) return 403rest_paste_lockedinstead. - Burn-after-read: returns
needs_reveal: truewith emptyfiles. SendPOST /pastes/{id}/reveal(withshare_hash) to reveal and consume it. A GET never reveals. Moderators never trigger the burn.
The author and moderators (the snipshare/moderate ability) can read every paste, including private, password-protected, trashed, and expired ones, but not burned ones.
Paste objects include a needs_reveal boolean.
Update Paste
Section titled “Update Paste”PUT /wp-json/snipshare/v1/pastes/{id}Owner or moderator only. Same body shape as create, with these differences:
| Field | On update |
|---|---|
files |
Files with an id are updated; files without one are added. Only files whose content, name or language changed get a revision. |
remove_files |
Array of file IDs to delete. A paste always keeps at least one file. |
password |
A non-empty value replaces the password. Omit it to keep the current one. |
remove_password |
true removes the password. |
expires_in |
Sets a new expiry counted from now. never removes the expiry. Omit it to keep the current one. |
tags |
Replaces the paste’s tags; [] removes them all. |
Burn-after-read cannot be turned on or off after creation.
Delete Paste (Trash)
Section titled “Delete Paste (Trash)”DELETE /wp-json/snipshare/v1/pastes/{id}Owner or moderator only. Sets status to trashed.
Fork Paste
Section titled “Fork Paste”POST /wp-json/snipshare/v1/pastes/{id}/forkAuth required. Clones all files into a new paste. Returns the new paste object.
Other members can fork only public pastes without a password and without burn-after-read. Authors can fork any of their own pastes, and the copy keeps the original’s visibility, password, and burn setting. A disallowed fork returns 403.
Toggle Star
Section titled “Toggle Star”POST /wp-json/snipshare/v1/pastes/{id}/starAuth required. Toggles star on/off. Response: { "starred": bool, "star_count": int }. You can only star pastes you can see; send share_hash for unlisted pastes.
Report Paste
Section titled “Report Paste”POST /wp-json/snipshare/v1/pastes/{id}/reportAuth required. Body: { "reason": "spam|inappropriate|malicious|copyright|other", "details": "optional text" }. You can only report pastes you can see; send share_hash for unlisted pastes.
Unlock Password-Protected Paste
Section titled “Unlock Password-Protected Paste”POST /wp-json/snipshare/v1/pastes/{id}/unlockBody: { "password": "secret", "share_hash": "..." }. share_hash is required for unlisted pastes. Returns 200 on success, 403 on wrong password.
Unlocking is per browser and lasts 1 hour. Logged-in users are tied to their login session. Guests get a random snipshare_visitor cookie (HttpOnly, SameSite=Lax, 1 day).
Wrong passwords are throttled: 5 failed attempts per 15 minutes per visitor IP per paste. After that the endpoint returns 429 rest_too_many_attempts with a Retry-After header. Change the limits with the snipshare_unlock_max_attempts, snipshare_unlock_window, and snipshare_client_ip filters.
List Revisions
Section titled “List Revisions”GET /wp-json/snipshare/v1/pastes/{id}/revisionsRequires full read access to the paste: the same rules as Get Paste, and a password-protected paste must be unlocked. Burn-after-read pastes never expose revisions.
Newest first. Paginated with page and per_page (default 50, maximum 100); the totals are in the X-WP-Total and X-WP-TotalPages headers. Filter to one file with file_id.
Each revision is one edit of one file: revision version N holds the file as it was at version N, and its change_note describes the edit from N to N+1. The live file is the version after the newest revision.
Get Diff
Section titled “Get Diff”GET /wp-json/snipshare/v1/pastes/{id}/diff?file_id=7&from=1&to=3Compares two versions of one file. to can be the live version (one past the newest revision), so the latest edit can be diffed. Returns from and to (the live side has id: 0), notes (the change notes of every edit between them, oldest first), current (the live version number) and diff_html (a side-by-side table that keeps indentation and blank lines). from must be lower than to; anything else returns 404. Requires the same full read access as List Revisions.
Raw Content
Section titled “Raw Content”GET /wp-json/snipshare/v1/pastes/{id}/rawGET /wp-json/snipshare/v1/pastes/{id}/raw/{file_id}After the access check, responds 307 redirecting to /paste/{hash}/raw/ or /paste/{hash}/raw/{filename}. Follow the redirect to get plain text.
Download
Section titled “Download”GET /wp-json/snipshare/v1/pastes/{id}/downloadAfter the access check, responds 307 redirecting to /paste/{hash}/download/, which returns a single file or ZIP archive.
Burn-after-read pastes refuse raw and download until revealed on the paste page.
Add File to Paste
Section titled “Add File to Paste”POST /wp-json/snipshare/v1/pastes/{id}/filesOwner only. Body: { "filename": "...", "content": "...", "language": "..." }.
Update File
Section titled “Update File”PUT /wp-json/snipshare/v1/pastes/{id}/files/{fid}Owner only. Body: any subset of filename, content, language.
Delete File
Section titled “Delete File”DELETE /wp-json/snipshare/v1/pastes/{id}/files/{fid}Owner only. Paste must retain at least one file.
Collections
Section titled “Collections”List My Collections
Section titled “List My Collections”GET /wp-json/snipshare/v1/collectionsAuth required. Returns the current user’s collections, newest first. Paginated with page and per_page (default 20, maximum 100); the totals are in the X-WP-Total and X-WP-TotalPages headers.
Create Collection
Section titled “Create Collection”POST /wp-json/snipshare/v1/collectionsBody: { "name": "...", "description": "...", "visibility": "public|private" }. The slug is made from the name and stays fixed when the collection is renamed, so its URL never changes.
Get Collection
Section titled “Get Collection”GET /wp-json/snipshare/v1/collections/{id}Owner for private, public for public collections. Returns paste summaries only, filtered to pastes the viewer may see. Each summary has: id, user_id, title, description, visibility, is_locked, file_count, star_count, fork_count, view_count, url, sort_order, created_at. File content and password data are never included.
Update Collection
Section titled “Update Collection”PUT /wp-json/snipshare/v1/collections/{id}Owner only. Updatable fields: name, description, visibility.
Delete Collection
Section titled “Delete Collection”DELETE /wp-json/snipshare/v1/collections/{id}Owner only. Pastes are not affected.
Add Paste to Collection
Section titled “Add Paste to Collection”POST /wp-json/snipshare/v1/collections/{id}/pastesBody: { "paste_id": 42 }. You can add your own pastes, or other members’ public, non-burn pastes. Adding someone else’s unlisted or private paste returns 404.
Remove Paste from Collection
Section titled “Remove Paste from Collection”DELETE /wp-json/snipshare/v1/collections/{id}/pastes/{paste_id}List All Tags
Section titled “List All Tags”GET /wp-json/snipshare/v1/tagsPublic. Returns tags sorted by count descending.
List Pastes by Tag
Section titled “List Pastes by Tag”GET /wp-json/snipshare/v1/tags/{slug}/pastesPublic. Returns public pastes with this tag. Supports global list params.
Admin Endpoints
Section titled “Admin Endpoints”Require the snipshare/moderate ability.
List Reports
Section titled “List Reports”GET /wp-json/snipshare/v1/admin/reports?status=pendingFilter by status: pending, reviewed, dismissed.
Review Report
Section titled “Review Report”PUT /wp-json/snipshare/v1/admin/reports/{id}Body: { "status": "reviewed|dismissed", "trash_paste": false }.
Force Paste Status
Section titled “Force Paste Status”PUT /wp-json/snipshare/v1/admin/pastes/{id}/statusBody: { "status": "active|trashed|expired" }.
Get Embed Data
Section titled “Get Embed Data”GET /wp-json/snipshare/v1/embed/{hash}Public. Returns lightweight paste data for embedding. Private, expired and trashed pastes return 404. Password-protected and burn-after-read pastes return a placeholder with no files: is_locked or needs_reveal set to true, plus title, share_hash and view_url.
Error Responses
Section titled “Error Responses”All errors follow the standard WP REST error format:
{ "code": "rest_forbidden", "message": "You do not have permission to do that.", "data": { "status": 403 }}Common error codes: rest_forbidden (403), rest_not_found (404), rest_invalid_param (400), snipshare_rate_limit_exceeded (429).
Paste access error codes:
| Code | Status | Meaning |
|---|---|---|
rest_paste_not_found |
404 | Paste does not exist or you may not know it exists (private, or unlisted without share_hash) |
rest_paste_expired |
410 | Paste expired or was burned |
rest_paste_locked |
403 | Content endpoint on a password-protected paste that is not unlocked |
rest_paste_needs_reveal |
403 | Content endpoint on a burn-after-read paste that is not revealed |
rest_too_many_attempts |
429 | Too many wrong passwords; see the Retry-After header |
rest_rate_limited |
429 | Hourly paste limit reached (create and fork) |
snipshare_paste_limit_reached |
403 | Member has reached the max pastes per member |
snipshare_feature_disabled |
400 / 403 | The request uses a feature the site owner switched off (400 for a create/update field, 403 for an action such as fork, star, report or collections) |
snipshare_paste_too_large |
413 | All files combined would exceed the max paste size |

