Skip to content

REST API Reference

SnipShare overviewPremiumGet SnipShare →

SnipShare exposes a complete REST API under the snipshare/v1 namespace. All endpoints are accessible at /wp-json/snipshare/v1/.


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 403 with the code snipshare_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.


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.


GET /wp-json/snipshare/v1/pastes

Returns 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.

POST /wp-json/snipshare/v1/pastes

Auth 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"
}
]
}
  • tags is a list of tag names. Responses return tags as objects (id, name, slug).
  • expires_in: never, 10m, 1h, 1d, 1w, 1M, 3M, 6M, or 1y.
  • 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 /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 with is_locked: true and empty files. Content endpoints (revisions, diff, raw, download) return 403 rest_paste_locked instead.
  • Burn-after-read: returns needs_reveal: true with empty files. Send POST /pastes/{id}/reveal (with share_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.

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 /wp-json/snipshare/v1/pastes/{id}

Owner or moderator only. Sets status to trashed.

POST /wp-json/snipshare/v1/pastes/{id}/fork

Auth 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.

POST /wp-json/snipshare/v1/pastes/{id}/star

Auth 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.

POST /wp-json/snipshare/v1/pastes/{id}/report

Auth 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.

POST /wp-json/snipshare/v1/pastes/{id}/unlock

Body: { "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.

GET /wp-json/snipshare/v1/pastes/{id}/revisions

Requires 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 /wp-json/snipshare/v1/pastes/{id}/diff?file_id=7&from=1&to=3

Compares 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.

GET /wp-json/snipshare/v1/pastes/{id}/raw
GET /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.

GET /wp-json/snipshare/v1/pastes/{id}/download

After 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.


POST /wp-json/snipshare/v1/pastes/{id}/files

Owner only. Body: { "filename": "...", "content": "...", "language": "..." }.

PUT /wp-json/snipshare/v1/pastes/{id}/files/{fid}

Owner only. Body: any subset of filename, content, language.

DELETE /wp-json/snipshare/v1/pastes/{id}/files/{fid}

Owner only. Paste must retain at least one file.


GET /wp-json/snipshare/v1/collections

Auth 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.

POST /wp-json/snipshare/v1/collections

Body: { "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 /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.

PUT /wp-json/snipshare/v1/collections/{id}

Owner only. Updatable fields: name, description, visibility.

DELETE /wp-json/snipshare/v1/collections/{id}

Owner only. Pastes are not affected.

POST /wp-json/snipshare/v1/collections/{id}/pastes

Body: { "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.

DELETE /wp-json/snipshare/v1/collections/{id}/pastes/{paste_id}

GET /wp-json/snipshare/v1/tags

Public. Returns tags sorted by count descending.

GET /wp-json/snipshare/v1/tags/{slug}/pastes

Public. Returns public pastes with this tag. Supports global list params.


Require the snipshare/moderate ability.

GET /wp-json/snipshare/v1/admin/reports?status=pending

Filter by status: pending, reviewed, dismissed.

PUT /wp-json/snipshare/v1/admin/reports/{id}

Body: { "status": "reviewed|dismissed", "trash_paste": false }.

PUT /wp-json/snipshare/v1/admin/pastes/{id}/status

Body: { "status": "active|trashed|expired" }.


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.


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