{ "info": { "_postman_id": "grav-api-collection-v1", "name": "Grav CMS API", "description": "Complete API collection for the Grav CMS RESTful API plugin.\n\n## Setup\n\n1. Set the `base_url` variable to your Grav site URL (e.g., `https://localhost/grav-api`)\n2. Set the `api_key` variable to a valid API key (generate via `bin/plugin api keys:generate`)\n3. Set `grav_environment` to your Grav environment (default: `localhost`)\n4. All requests include `X-API-Key` and `X-Grav-Environment` headers automatically\n\n## Authentication\n\nAll requests (except `/auth/*` endpoints) require the `X-API-Key` header.\nThe `X-Grav-Environment` header is included on all requests to ensure correct environment context.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "variable": [ { "key": "base_url", "value": "http://localhost", "type": "string" }, { "key": "api_key", "value": "grav_your_api_key_here", "type": "string" }, { "key": "access_token", "value": "", "type": "string" }, { "key": "refresh_token", "value": "", "type": "string" }, { "key": "api_prefix", "value": "/api/v1", "type": "string" }, { "key": "test_username", "value": "testuser", "type": "string" }, { "key": "test_api_key_id", "value": "", "type": "string" }, { "key": "grav_environment", "value": "localhost", "type": "string" }, { "key": "page_route", "value": "blog", "type": "string" }, { "key": "lang", "value": "en", "type": "string" }, { "key": "package_slug", "value": "", "type": "string" }, { "key": "webhook_id", "value": "", "type": "string" }, { "key": "notification_id", "value": "", "type": "string" }, { "key": "username", "value": "admin", "type": "string" }, { "key": "password", "value": "", "type": "string" }, { "key": "test_page_route", "value": "", "type": "string" } ], "item": [ { "name": "Setup", "description": "Setup requests that run before all other tests. Creates test data and authenticates.", "item": [ { "name": "Setup: Login", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test(\"Status is 200\", () => pm.response.to.have.status(200));", "pm.test(\"Has access_token\", () => pm.expect(res.data).to.have.property(\"access_token\"));", "", "if (res.data && res.data.access_token) {", " pm.collectionVariables.set(\"access_token\", res.data.access_token);", " pm.collectionVariables.set(\"refresh_token\", res.data.refresh_token);", "}" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"{{username}}\",\n \"password\": \"{{password}}\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/token", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "token" ] }, "description": "Authenticate and save access_token and refresh_token to collection variables." } }, { "name": "Setup: Create Test Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "if (res.data && res.data.route) {", " pm.collectionVariables.set('test_page_route', res.data.route);", "}", "", "pm.test('Status is 201', () => pm.response.to.have.status(201));", "pm.test('Has route', () => pm.expect(res.data).to.have.property('route'));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"route\": \"/newman-test-page\",\n \"title\": \"Newman Test Page\",\n \"template\": \"default\",\n \"content\": \"# Test Page\\nCreated by Newman test runner.\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages" ] }, "description": "Create a test page used by subsequent tests. Saves the route to test_page_route." } }, { "name": "Setup: Create Test Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test(\"Status is 201\", () => pm.response.to.have.status(201));", "", "if (res.data && res.data.id) {", " pm.collectionVariables.set(\"webhook_id\", res.data.id);", "}" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"url\": \"https://httpbin.org/post\",\n \"events\": [\n \"page.created\"\n ],\n \"secret\": \"newman-test-secret\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks" ] }, "description": "Create a test webhook. Saves the webhook_id to collection variables." } } ] }, { "name": "Auth", "description": "Authentication endpoints. These do not require prior authentication.", "item": [ { "name": "Login (Get JWT Tokens)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "if (res.data && res.data.access_token) {", " pm.collectionVariables.set('access_token', res.data.access_token);", " pm.collectionVariables.set('refresh_token', res.data.refresh_token);", "}", "", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has access_token', () => pm.expect(res.data).to.have.property('access_token'));", "pm.test('Has refresh_token', () => pm.expect(res.data).to.have.property('refresh_token'));", "pm.test('Token type is Bearer', () => pm.expect(res.data.token_type).to.equal('Bearer'));", "pm.test('Has expires_in', () => pm.expect(res.data.expires_in).to.be.a('number'));" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"{{username}}\",\n \"password\": \"{{password}}\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/token", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "token" ] }, "description": "Exchange username/password for JWT access and refresh tokens. The access token is automatically saved for use by other requests." } }, { "name": "Refresh Token", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "if (res.data && res.data.access_token) {", " pm.collectionVariables.set('access_token', res.data.access_token);", " pm.collectionVariables.set('refresh_token', res.data.refresh_token);", "}", "", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('New tokens issued', () => pm.expect(res.data).to.have.property('access_token'));" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"refresh_token\": \"{{refresh_token}}\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/refresh", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "refresh" ] }, "description": "Exchange a refresh token for a new access/refresh token pair. The old refresh token is revoked (token rotation)." } }, { "name": "Revoke Token", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"refresh_token\": \"{{refresh_token}}\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/revoke", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "revoke" ] }, "description": "Revoke a refresh token, preventing it from being used to generate new access tokens." } } ] }, { "name": "Pages", "description": "Content management \u2014 create, read, update, delete, move, and copy pages.", "item": [ { "name": "List Pages", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));", "pm.test('Has pagination meta', () => pm.expect(res.meta.pagination).to.have.property('total'));", "pm.test('Has links', () => pm.expect(res.links).to.have.property('self'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages?page=1&per_page=20", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages" ], "query": [ { "key": "page", "value": "1" }, { "key": "per_page", "value": "20" }, { "key": "sort", "value": "date", "disabled": true }, { "key": "order", "value": "desc", "disabled": true }, { "key": "published", "value": "true", "disabled": true }, { "key": "template", "value": "post", "disabled": true }, { "key": "routable", "value": "true", "disabled": true }, { "key": "visible", "value": "true", "disabled": true }, { "key": "parent", "value": "blog", "disabled": true } ] }, "description": "List all pages with filtering, sorting, and pagination.\n\n**Filters** (enable as needed):\n- `published` - true/false\n- `template` - page template name\n- `routable` - true/false\n- `visible` - true/false\n- `parent` - parent route prefix\n\n**Sorting**: `sort` (date, title, slug, modified, order) + `order` (asc, desc)", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Pages (Filtered: Blog Posts)", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages?published=true&template=post&parent=blog&sort=date&order=desc", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages" ], "query": [ { "key": "published", "value": "true" }, { "key": "template", "value": "post" }, { "key": "parent", "value": "blog" }, { "key": "sort", "value": "date" }, { "key": "order", "value": "desc" } ] }, "description": "Example: List published blog posts, newest first.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has route', () => pm.expect(res.data).to.have.property('route'));", "pm.test('Has title', () => pm.expect(res.data).to.have.property('title'));", "pm.test('Has content', () => pm.expect(res.data).to.have.property('content'));", "pm.test('Has ETag header', () => pm.response.to.have.header('ETag'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog" ] }, "description": "Get a single page by route. Returns full content, frontmatter, taxonomy, and media list.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Page (Rendered HTML + Children)", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog?render=true&children=true&children_depth=2", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog" ], "query": [ { "key": "render", "value": "true" }, { "key": "children", "value": "true" }, { "key": "children_depth", "value": "2" } ] }, "description": "Get a page with rendered HTML content and child pages up to 2 levels deep.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 201', () => pm.response.to.have.status(201));", "pm.test('Has Location header', () => pm.response.to.have.header('Location'));", "pm.test('Has route', () => pm.expect(res.data).to.have.property('route'));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"route\": \"/newman-test-create-{{$timestamp}}\",\n \"title\": \"Newman Created Page\",\n \"template\": \"default\",\n \"content\": \"# Test Page\\n\\nCreated by Newman with timestamp.\",\n \"header\": {\n \"taxonomy\": {\n \"category\": [\"test\"],\n \"tag\": [\"api\", \"newman\"]\n },\n \"published\": true\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages" ] }, "description": "Create a new page. Requires `route` and `title`. Optional: `template`, `content`, `header` (frontmatter), `order`." } }, { "name": "Update Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has updated content', () => pm.expect(res.data).to.have.property('content'));" ] } } ], "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" }, { "key": "If-Match", "value": "\"etag-from-get-request\"", "description": "Optional: ETag from a previous GET for conflict detection", "disabled": true } ], "body": { "mode": "raw", "raw": "{\n \"title\": \"Updated Blog Post Title\",\n \"content\": \"# Updated Content\\n\\nThis content was updated via the API.\",\n \"header\": {\n \"taxonomy\": {\n \"tag\": [\"api\", \"grav\", \"updated\"]\n }\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/newman-test-page", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "test", "newman-page" ] }, "description": "Partial update \u2014 only send the fields you want to change. Supports `content`, `title`, `header`, `template`, `published`, `visible`.\n\nEnable the `If-Match` header for optimistic concurrency control." } }, { "name": "Move Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"parent\": \"/\",\n \"slug\": \"newman-moved-page\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/newman-test-page/move", "host": [ "{{base_url}}{{api_prefix}}/pages/newman-test-page/move" ], "path": [ "pages", "test", "newman-page", "move" ] }, "description": "Move a page to a new parent and/or rename its slug. Requires `parent`. Optional: `slug`, `order`." } }, { "name": "Copy Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));", "pm.test('Has Location header', () => pm.response.to.have.header('Location'));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"route\": \"/newman-test-copy\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/newman-test-page/copy", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "test", "newman-page", "copy" ] }, "description": "Copy a page (and its media) to a new route." } }, { "name": "Delete Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/newman-test-copy?children=true", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "test", "newman-copy" ], "query": [ { "key": "children", "value": "true", "description": "Set to true to also delete child pages" } ] }, "description": "Delete a page. If the page has children and `children=true` is not set, returns a 422 error requiring confirmation.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Taxonomy", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res.data).to.be.an('object'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/taxonomy", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "taxonomy" ] }, "description": "List all taxonomy types (categories, tags, etc.) and their values across all pages.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Root Children (Lazy Load)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Returns array', () => pm.expect(pm.response.json().data).to.be.an('array'));", "pm.test('Pages have has_children field', () => {", " const pages = pm.response.json().data;", " if (pages.length > 0) {", " pm.expect(pages[0]).to.have.property('has_children');", " }", "});" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/pages?children_of=/&sort=order", "host": [ "{{base_url}}{{api_prefix}}/pages?children_of=/&sort=order" ] }, "description": "Get only root-level pages (direct children of /). Returns has_children boolean for each page. Ideal for lazy-loading tree views and miller columns." }, "response": [] }, { "name": "List Children of /blog", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('All pages are direct children of /blog', () => {", " const pages = pm.response.json().data;", " pages.forEach(p => {", " pm.expect(p.route).to.match(/^\\/blog\\/[^\\/]+$/);", " });", "});" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/pages?children_of=/blog&sort=order", "host": [ "{{base_url}}{{api_prefix}}/pages?children_of=/blog&sort=order" ] }, "description": "Get direct children of /blog only (one level deep). Unlike parent filter, children_of does not return deeper descendants." }, "response": [] } ] }, { "name": "Media", "description": "Media management \u2014 upload, list, and delete media files for pages and the site.", "item": [ { "name": "List Page Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/media", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "media" ] }, "description": "List all media files attached to a specific page.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Upload Page Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "body": { "mode": "formdata", "formdata": [ { "key": "file", "type": "file", "src": "", "description": "Select a file to upload" } ] }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/media", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "media" ] }, "description": "Upload one or more media files to a page. Use multipart/form-data. Files are validated against Grav's security config for dangerous extensions.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Delete Page Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/media/photo.jpg", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "media", "photo.jpg" ] }, "description": "Delete a specific media file from a page.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Site Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/media?page=1&per_page=20", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media" ], "query": [ { "key": "page", "value": "1" }, { "key": "per_page", "value": "20" }, { "key": "path", "value": "", "description": "Subfolder path relative to user/media", "disabled": true }, { "key": "search", "value": "", "description": "Recursive filename search across all subfolders", "disabled": true }, { "key": "type", "value": "image", "description": "Filter by type: image, video, audio, document", "disabled": true } ] }, "description": "List site-level media files and folders from user/media. Supports subfolder browsing via path, recursive search, and type filtering. Response includes folders array in meta.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Upload Site Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "body": { "mode": "formdata", "formdata": [ { "key": "file", "type": "file", "src": "", "description": "Select a file to upload" } ] }, "url": { "raw": "{{base_url}}{{api_prefix}}/media", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media" ], "query": [ { "key": "path", "value": "", "description": "Subfolder path to upload into (created automatically)", "disabled": true } ] }, "description": "Upload media files to the site-level media folder (user/media). Optionally specify a subfolder path.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Delete Site Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/media/logo.png", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media", "logo.png" ] }, "description": "Delete a site-level media file. Filename may include a subfolder path (e.g. blog/hero.jpg).", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create Media Folder", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "body": { "mode": "raw", "raw": "{\n \"path\": \"blog/2026\"\n}", "options": { "raw": { "language": "json" } } }, "url": { "raw": "{{base_url}}{{api_prefix}}/media/folders", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media", "folders" ] }, "description": "Create a new folder in the site-level media directory.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Delete Media Folder", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/media/folders/blog/2026", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media", "folders", "blog", "2026" ] }, "description": "Delete an empty folder from the site-level media directory.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Rename Site Media", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "body": { "mode": "raw", "raw": "{\n \"from\": \"blog/hero.jpg\",\n \"to\": \"blog/banner.jpg\"\n}", "options": { "raw": { "language": "json" } } }, "url": { "raw": "{{base_url}}{{api_prefix}}/media/rename", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media", "rename" ] }, "description": "Rename or move a media file within the site-level media directory.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Rename Media Folder", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "body": { "mode": "raw", "raw": "{\n \"from\": \"blog/old-name\",\n \"to\": \"blog/new-name\"\n}", "options": { "raw": { "language": "json" } } }, "url": { "raw": "{{base_url}}{{api_prefix}}/media/folders/rename", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "media", "folders", "rename" ] }, "description": "Rename a folder within the site-level media directory.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Config", "description": "Configuration management \u2014 read and update system, site, plugin, and theme configs.", "item": [ { "name": "Get System Config", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res.data).to.be.an('object'));", "pm.test('Has ETag', () => pm.response.to.have.header('ETag'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/config/system", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "system" ] }, "description": "Read the system configuration.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Site Config", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/config/site", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "site" ] }, "description": "Read the site configuration (site.yaml).", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Plugin Config", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/config/plugins/markdown", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "plugins", "markdown" ] }, "description": "Read configuration for a specific plugin. Change `markdown` to any plugin name.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Theme Config", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/config/themes/quark", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "themes", "quark" ] }, "description": "Read configuration for a specific theme.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Update Site Config", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has updated data', () => pm.expect(res.data).to.be.an('object'));" ] } } ], "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" }, { "key": "If-Match", "value": "\"etag-from-get\"", "disabled": true } ], "body": { "mode": "raw", "raw": "{\n \"title\": \"My Updated Site Title\",\n \"metadata\": {\n \"description\": \"Updated via the Grav API\"\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/config/site", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "site" ] }, "description": "Update site configuration. Values are deep-merged with existing config. Only send the fields you want to change." } }, { "name": "Update Plugin Config", "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"extra\": true,\n \"auto_line_breaks\": false\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/config/plugins/markdown", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "config", "plugins", "markdown" ] }, "description": "Update a plugin's configuration." } } ] }, { "name": "Users", "description": "User account management and API key administration.", "item": [ { "name": "List Users", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));", "pm.test('Has pagination', () => pm.expect(res.meta.pagination).to.have.property('total'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/users?page=1&per_page=20", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users" ], "query": [ { "key": "page", "value": "1" }, { "key": "per_page", "value": "20" } ] }, "description": "List all user accounts (paginated). Sensitive fields (password, API key hashes) are excluded.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get User", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has username', () => pm.expect(res.data).to.have.property('username'));", "pm.test('No password field', () => pm.expect(res.data).to.not.have.property('hashed_password'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/users/admin", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "admin" ] }, "description": "Get details for a specific user.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create User", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"{{test_username}}\",\n \"password\": \"SecureP@ssw0rd!\",\n \"email\": \"testuser@example.com\",\n \"fullname\": \"Test User\",\n \"title\": \"Editor\",\n \"access\": {\n \"api\": {\n \"access\": true,\n \"pages\": {\n \"read\": true,\n \"write\": true\n }\n }\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/users", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users" ] }, "description": "Create a new user account. Required: `username`, `password`, `email`." } }, { "name": "Update User", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"fullname\": \"Updated Test User\",\n \"title\": \"Senior Editor\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}" ] }, "description": "Partial update a user. Only send the fields you want to change." } }, { "name": "List API Keys", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/api-keys", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "api-keys" ] }, "description": "List all API keys for a user. Returns metadata only (no hashes).", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create API Key", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 201', () => pm.response.to.have.status(201));", "pm.test('Has raw key', () => pm.expect(res.data).to.have.property('key'));", "pm.test('Key starts with grav_', () => pm.expect(res.data.key).to.match(/^grav_/));", "", "if (res.data && res.data.id) {", " pm.collectionVariables.set('test_api_key_id', res.data.id);", "}" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"name\": \"Test CLI Key\",\n \"scopes\": [\"api.pages.read\", \"api.pages.write\"],\n \"expiry_days\": 90\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/api-keys", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "api-keys" ] }, "description": "Generate a new API key. The raw key is returned ONCE \u2014 save it immediately. The key ID is saved to the `test_api_key_id` variable for the revoke request." } }, { "name": "Revoke API Key", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/api-keys/{{test_api_key_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "api-keys", "{{test_api_key_id}}" ] }, "description": "Revoke (delete) a specific API key.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Upload Avatar", "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/avatar", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "avatar" ] }, "description": "Upload a custom avatar image for a user.", "body": { "mode": "formdata", "formdata": [ { "key": "avatar", "type": "file", "src": "" } ] } } }, { "name": "Delete Avatar", "request": { "method": "DELETE", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/avatar", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "avatar" ] }, "description": "Remove the user's custom avatar." } }, { "name": "Generate 2FA Secret", "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}/2fa", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}", "2fa" ] }, "description": "Generate a new TOTP 2FA secret and return the QR code as a data URI." } }, { "name": "Delete User", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/users/{{test_username}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "{{test_username}}" ] }, "description": "Delete a user account. You cannot delete yourself.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "System", "description": "System administration \u2014 info, cache, logs, and backups.", "item": [ { "name": "Ping / Keep-Alive", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/ping", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "ping" ] }, "description": "Lightweight health check endpoint. Returns {pong: true}. Useful for session keep-alive." } }, { "name": "System Info", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has grav_version', () => pm.expect(res.data).to.have.property('grav_version'));", "pm.test('Has php_version', () => pm.expect(res.data).to.have.property('php_version'));", "pm.test('Has plugins', () => pm.expect(res.data).to.have.property('plugins'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/system/info", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "system", "info" ] }, "description": "Get system information: Grav version, PHP version, extensions, plugins, themes, and environment.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Clear Cache (Standard)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/cache?scope=standard", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "cache" ], "query": [ { "key": "scope", "value": "standard", "description": "Options: all, standard, images, assets, tmp" } ] }, "description": "Clear the Grav cache. Scopes: `all`, `standard`, `images`, `assets`, `tmp`.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Clear Cache (All)", "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/cache?scope=all", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "cache" ], "query": [ { "key": "scope", "value": "all" } ] }, "description": "Clear ALL caches including images and assets.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "View Logs", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/system/logs?page=1&per_page=50", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "system", "logs" ], "query": [ { "key": "page", "value": "1" }, { "key": "per_page", "value": "50" }, { "key": "level", "value": "error", "disabled": true, "description": "Filter: error, warning, info, debug" } ] }, "description": "Read Grav log entries. Optional `level` filter for error/warning/info/debug.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create Backup", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "url": { "raw": "{{base_url}}{{api_prefix}}/system/backup", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "system", "backup" ] }, "description": "Create a new site backup.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Backups", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/system/backups", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "system", "backups" ] }, "description": "List all available backups.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Languages", "description": "Site language configuration and multi-language support.", "item": [ { "name": "List Site Languages", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/languages", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "languages" ] }, "description": "List all configured site languages and their status.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Pages / Multi-Language", "description": "Multi-language page operations \u2014 translations, language-specific content.", "item": [ { "name": "Get Page in Language", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/{{page_route}}?lang={{lang}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "{{page_route}}" ], "query": [ { "key": "lang", "value": "{{lang}}" } ] }, "description": "Get a page in a specific language.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Get Page Translations", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/{{page_route}}/languages", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "{{page_route}}", "languages" ] }, "description": "List all available translations for a page.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create Translation", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"lang\": \"fr\",\n \"title\": \"Mon titre\",\n \"content\": \"# Contenu\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/{{page_route}}/translate", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "{{page_route}}", "translate" ] }, "description": "Create a new translation for a page in a specific language." } }, { "name": "Update Page in Language", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"title\": \"Updated\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/{{page_route}}?lang={{lang}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "{{page_route}}" ], "query": [ { "key": "lang", "value": "{{lang}}" } ] }, "description": "Update a page in a specific language." } }, { "name": "Delete Language File", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/{{page_route}}?lang=fr", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "{{page_route}}" ], "query": [ { "key": "lang", "value": "fr" } ] }, "description": "Delete a specific language file for a page.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Pages / Batch Operations", "description": "Batch page operations \u2014 reorder children, bulk publish, bulk delete.", "item": [ { "name": "Reorder Children", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"order\": [\"sunshine-in-the-hills\", \"london-at-night\", \"forest-in-the-fog\"]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/reorder", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "reorder" ] }, "description": "Reorder child pages under a parent page." } }, { "name": "Batch Publish", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"operation\": \"publish\",\n \"routes\": [\"/newman-test-page\"]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/batch", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "batch" ] }, "description": "Batch publish multiple pages at once." } }, { "name": "Batch Delete", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"operation\": \"delete\",\n \"routes\": [\n \"/newman-test-copy\"\n ]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/batch", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "batch" ] }, "description": "Batch delete multiple pages at once." } }, { "name": "Reorganize Pages", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));", "pm.test('Each result has route and slug', () => {", " res.data.forEach(item => {", " pm.expect(item).to.have.property('route');", " pm.expect(item).to.have.property('slug');", " pm.expect(item).to.have.property('parent');", " });", "});" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"operations\": [\n { \"route\": \"/blog/sunshine-in-the-hills\", \"position\": 2 },\n { \"route\": \"/blog/london-at-night\", \"position\": 1 }\n ]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/reorganize", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "reorganize" ] }, "description": "Reorganize multiple pages atomically \u2014 move across parents and/or reorder within the same request. Each operation specifies a page route and optionally a new parent and/or position. All operations are validated before any changes are applied." } } ] }, { "name": "GPM", "description": "Grav Package Manager \u2014 manage plugins, themes, updates, and the repository.", "item": [ { "name": "GPM / Installed", "description": "List and inspect installed plugins and themes.", "item": [ { "name": "List Installed Plugins", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins" ] }, "description": "List all installed plugins with their versions and status.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Plugin Details", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}" ] }, "description": "Get details for a specific installed plugin.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "List Installed Themes", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/themes", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "themes" ] }, "description": "List all installed themes with their versions and status.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Theme Details", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/themes/{{package_slug}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "themes", "{{package_slug}}" ] }, "description": "Get details for a specific installed theme.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Plugin README", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}/readme", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}", "readme" ] }, "description": "Get the README.md content for an installed plugin." } }, { "name": "Plugin Changelog", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}/changelog", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}", "changelog" ] }, "description": "Get the CHANGELOG.md content for an installed plugin." } }, { "name": "Theme README", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/themes/{{package_slug}}/readme", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "themes", "{{package_slug}}", "readme" ] }, "description": "Get the README.md content for an installed theme." } }, { "name": "Theme Changelog", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/themes/{{package_slug}}/changelog", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "themes", "{{package_slug}}", "changelog" ] }, "description": "Get the CHANGELOG.md content for an installed theme." } } ] }, { "name": "GPM / Updates", "description": "Check for available updates.", "item": [ { "name": "Check Updates", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/updates", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "updates" ] }, "description": "Check for available updates to plugins, themes, and Grav core.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Check Updates (flush cache)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/updates?flush=true", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "updates" ], "query": [ { "key": "flush", "value": "true" } ] }, "description": "Check for updates with cache flushed to get the latest information.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "GPM / Install & Remove", "description": "Install and remove packages.", "item": [ { "name": "Install Plugin", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"package\": \"admin\",\n \"type\": \"plugin\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/install", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "install" ] }, "description": "Install a plugin from the GPM repository. For premium packages, add a `license` field: `\"license\": \"XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX\"`." } }, { "name": "Install Theme", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"package\": \"quark\",\n \"type\": \"theme\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/install", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "install" ] }, "description": "Install a theme from the GPM repository. For premium themes, add a `license` field: `\"license\": \"XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX\"`." } }, { "name": "Remove Package", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"package\": \"some-plugin\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/remove", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "remove" ] }, "description": "Remove an installed plugin or theme." } }, { "name": "Direct Install from URL", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"url\": \"https://example.com/package.zip\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/direct-install", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "direct-install" ] }, "description": "Install a package directly from a URL (zip file)." } } ] }, { "name": "GPM / Update", "description": "Update packages and Grav core.", "item": [ { "name": "Update Package", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"package\": \"admin\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/update", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "update" ] }, "description": "Update a specific package to the latest version." } }, { "name": "Update All", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/update-all", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "update-all" ] }, "description": "Update all installed packages to their latest versions." } }, { "name": "Upgrade Grav", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/upgrade", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "upgrade" ] }, "description": "Upgrade Grav core to the latest version." } } ] }, { "name": "GPM / Repository", "description": "Browse and search the GPM repository for available packages.", "item": [ { "name": "Search Packages", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/search?q=email", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "search" ], "query": [ { "key": "q", "value": "email", "description": "Search query (matches slug, name, description, author, keywords)" } ] }, "description": "Search across all plugins and themes in the GPM repository by keyword.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Browse Repository Plugins", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/repository/plugins", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "repository", "plugins" ], "query": [ { "key": "q", "value": "", "description": "Optional keyword filter (matches slug, name, description, author, keywords)", "disabled": true } ] }, "description": "Browse available plugins in the GPM repository. Use ?q=keyword to filter.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Browse Repository Themes", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/repository/themes", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "repository", "themes" ], "query": [ { "key": "q", "value": "", "description": "Optional keyword filter (matches slug, name, description, author, keywords)", "disabled": true } ] }, "description": "Browse available themes in the GPM repository. Use ?q=keyword to filter.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Repository Package Details", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/repository/{{package_slug}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "repository", "{{package_slug}}" ] }, "description": "Get details for a specific package in the GPM repository.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "GPM / Plugin Pages", "description": "Plugin admin page definitions and custom web component scripts.", "item": [ { "name": "Plugin Page Definition", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));", "pm.test('Has required fields', () => {", " const d = res.data;", " pm.expect(d).to.have.property('id');", " pm.expect(d).to.have.property('plugin');", " pm.expect(d).to.have.property('title');", " pm.expect(d).to.have.property('page_type');", " pm.expect(d).to.have.property('has_custom_component');", "});" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}/page", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}", "page" ] }, "description": "Get the admin page definition for a plugin. Returns page metadata, blueprint reference, data/save endpoints, and available actions.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Plugin Page Script", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Content-Type is JavaScript', () => {", " pm.expect(pm.response.headers.get('Content-Type')).to.include('application/javascript');", "});" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}/page-script", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}", "page-script" ] }, "description": "Get the JavaScript web component script for a plugin's custom admin page. Returns application/javascript content.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Plugin Report Script", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Content-Type is JavaScript', () => {", " pm.expect(pm.response.headers.get('Content-Type')).to.include('application/javascript');", "});" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/gpm/plugins/{{package_slug}}/report-script/{{report_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "gpm", "plugins", "{{package_slug}}", "report-script", "{{report_id}}" ] }, "description": "Get the JavaScript web component script for a plugin's report. Returns application/javascript content. The reportId matches the component field from the /reports endpoint response.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] } ] }, { "name": "Scheduler", "description": "Scheduler management \u2014 list jobs, view status, check history, and run the scheduler.", "item": [ { "name": "List Jobs", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/scheduler/jobs", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "scheduler", "jobs" ] }, "description": "List all configured scheduler jobs.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Scheduler Status", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/scheduler/status", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "scheduler", "status" ] }, "description": "Get the current scheduler status and cron configuration.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Job History", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/scheduler/history", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "scheduler", "history" ] }, "description": "View the history of scheduler job executions.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Run Scheduler", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"force\": false\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/scheduler/run", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "scheduler", "run" ] }, "description": "Trigger the scheduler to run. Set force to true to run regardless of schedule." } } ] }, { "name": "System Info", "description": "System info and diagnostics overview.", "item": [ { "name": "System Info", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/systeminfo", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "systeminfo" ] }, "description": "Get system info overview including environment checks and diagnostics.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Reports", "description": "Plugin-extensible diagnostic reports.", "item": [ { "name": "Get Reports", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/reports", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "reports" ] }, "description": "Get plugin-extensible diagnostic reports including security check, YAML linting, and plugin-provided reports.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Sidebar", "description": "Admin sidebar navigation items contributed by plugins.", "item": [ { "name": "Get Sidebar Items", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data array', () => pm.expect(res.data).to.be.an('array'));", "pm.test('Items have required fields', () => {", " if (res.data.length > 0) {", " const item = res.data[0];", " pm.expect(item).to.have.property('id');", " pm.expect(item).to.have.property('plugin');", " pm.expect(item).to.have.property('label');", " pm.expect(item).to.have.property('icon');", " pm.expect(item).to.have.property('route');", " pm.expect(item).to.have.property('priority');", " }", "});" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/sidebar/items", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "sidebar", "items" ] }, "description": "Get all admin sidebar navigation items contributed by installed plugins.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Dashboard", "description": "Dashboard data \u2014 notifications, news feed, and statistics.", "item": [ { "name": "Get Notifications", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/dashboard/notifications", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "dashboard", "notifications" ] }, "description": "Get all dashboard notifications.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Hide Notification", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/dashboard/notifications/{{notification_id}}/hide", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "dashboard", "notifications", "{{notification_id}}", "hide" ] }, "description": "Hide a specific notification by ID." } }, { "name": "News Feed", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/dashboard/feed", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "dashboard", "feed" ] }, "description": "Get the dashboard news feed.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Dashboard Stats", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/dashboard/stats", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "dashboard", "stats" ] }, "description": "Get dashboard statistics (page counts, user counts, etc.).", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Dashboard Popularity", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has summary', () => pm.expect(res.data).to.have.property('summary'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/dashboard/popularity", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "dashboard", "popularity" ] }, "description": "Get page view statistics including daily chart data (last 14 days), summary counters, and top pages by views.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "Webhooks", "description": "Webhook management \u2014 create, update, delete, and test webhooks.", "item": [ { "name": "List Webhooks", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks" ] }, "description": "List all configured webhooks.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Create Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 201', () => pm.response.to.have.status(201));", "", "if (res.data && res.data.id) {", " pm.collectionVariables.set('webhook_id', res.data.id);", "}" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"url\": \"https://example.com/webhook\",\n \"events\": [\"page.created\", \"page.updated\"],\n \"enabled\": true\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks" ] }, "description": "Create a new webhook. The webhook ID is automatically saved to the `webhook_id` variable." } }, { "name": "Get Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}" ] }, "description": "Get details for a specific webhook.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Update Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "PATCH", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"events\": [\"page.created\", \"page.updated\", \"page.deleted\"]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}" ] }, "description": "Update an existing webhook configuration." } }, { "name": "Delete Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 204', () => pm.response.to.have.status(204));" ] } } ], "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}" ] }, "description": "Delete a webhook.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Webhook Deliveries", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has data', () => pm.expect(res).to.have.property('data'));" ] } } ], "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}/deliveries", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}", "deliveries" ] }, "description": "View delivery history for a specific webhook.", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "Test Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}/test", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}", "test" ] }, "description": "Send a test payload to a webhook endpoint." } } ] }, { "name": "Workflows", "description": "Multi-step workflow examples that chain API calls together.", "item": [ { "name": "01. Create Blog Post with Media", "item": [ { "name": "1. Create the page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 201', () => pm.response.to.have.status(201));" ] } } ], "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"route\": \"/blog/api-workflow-test\",\n \"title\": \"API Workflow Test Post\",\n \"template\": \"post\",\n \"content\": \"# Workflow Test\\n\\nThis post was created as part of an API workflow test.\\n\\n![Hero Image](hero.jpg)\",\n \"header\": {\n \"taxonomy\": {\n \"category\": [\"blog\"],\n \"tag\": [\"api\", \"test\"]\n },\n \"published\": true\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages" ] } } }, { "name": "2. Upload hero image", "request": { "method": "POST", "body": { "mode": "formdata", "formdata": [ { "key": "file", "type": "file", "src": "", "description": "Select hero.jpg" } ] }, "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/api-workflow-test/media", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "api-workflow-test", "media" ] }, "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "3. Verify the page", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/api-workflow-test?render=true", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "api-workflow-test" ], "query": [ { "key": "render", "value": "true" } ] }, "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "4. Cleanup - delete the page", "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/pages/blog/api-workflow-test?children=true", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "blog", "api-workflow-test" ], "query": [ { "key": "children", "value": "true" } ] }, "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] }, { "name": "02. Full User Lifecycle", "item": [ { "name": "1. Create user", "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"workflow-user\",\n \"password\": \"T3stP@ss!\",\n \"email\": \"workflow@example.com\",\n \"fullname\": \"Workflow User\",\n \"access\": {\n \"api\": { \"access\": true, \"pages\": { \"read\": true } }\n }\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/users", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users" ] } } }, { "name": "2. Generate API key for user", "request": { "method": "POST", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"name\": \"Workflow Test Key\",\n \"scopes\": [\"api.pages.read\"]\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/users/workflow-user/api-keys", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "workflow-user", "api-keys" ] } } }, { "name": "3. Login as user (get JWT)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "const res = pm.response.json();", "if (res.data) {", " pm.collectionVariables.set('access_token', res.data.access_token);", " pm.collectionVariables.set('refresh_token', res.data.refresh_token);", "}" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"workflow-user\",\n \"password\": \"T3stP@ss!\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/token", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "token" ] } } }, { "name": "4. List API keys", "request": { "method": "GET", "url": { "raw": "{{base_url}}{{api_prefix}}/users/workflow-user/api-keys", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "workflow-user", "api-keys" ] }, "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } }, { "name": "5. Cleanup - delete user", "request": { "method": "DELETE", "url": { "raw": "{{base_url}}{{api_prefix}}/users/workflow-user", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "users", "workflow-user" ] }, "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ] } } ] } ] }, { "name": "Blueprints", "item": [ { "name": "List Page Types", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Returns array', () => pm.expect(pm.response.json().data).to.be.an('array'));", "pm.test('Items have type and label', () => {", " const items = pm.response.json().data;", " if (items.length > 0) {", " pm.expect(items[0]).to.have.property('type');", " pm.expect(items[0]).to.have.property('label');", " }", "});" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/pages", "host": [ "{{base_url}}{{api_prefix}}/blueprints/pages" ] }, "description": "List all available page template types in the active theme." }, "response": [] }, { "name": "Get Page Blueprint (default)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has name', () => pm.expect(pm.response.json().data.name).to.equal('default'));", "pm.test('Has fields', () => pm.expect(pm.response.json().data.fields).to.be.an('array'));", "pm.test('Has validation', () => pm.expect(pm.response.json().data).to.have.property('validation'));" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/pages/default", "host": [ "{{base_url}}{{api_prefix}}/blueprints/pages/default" ] }, "description": "Get the resolved blueprint for the default page template. Includes all inherited fields from extends@ and import@ directives." }, "response": [] }, { "name": "Get Page Blueprint (blog)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has blog-specific fields', () => {", " const data = pm.response.json().data;", " pm.expect(data.fields).to.be.an('array');", "});" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/pages/blog", "host": [ "{{base_url}}{{api_prefix}}/blueprints/pages/blog" ] }, "description": "Get the resolved blueprint for the blog page template." }, "response": [] }, { "name": "Get Plugin Blueprint", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has fields', () => pm.expect(pm.response.json().data.fields).to.be.an('array'));", "pm.test('Has name', () => pm.expect(pm.response.json().data.name).to.equal('email'));" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/plugins/email", "host": [ "{{base_url}}{{api_prefix}}/blueprints/plugins/email" ] }, "description": "Get the configuration blueprint for the email plugin." }, "response": [] }, { "name": "Get Theme Blueprint", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has fields', () => pm.expect(pm.response.json().data.fields).to.be.an('array'));" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/themes/quark", "host": [ "{{base_url}}{{api_prefix}}/blueprints/themes/quark" ] }, "description": "Get the configuration blueprint for the quark theme." }, "response": [] }, { "name": "Get Config Blueprint (system)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has fields', () => pm.expect(pm.response.json().data.fields).to.be.an('array'));", "pm.test('Has name', () => pm.expect(pm.response.json().data.name).to.equal('system'));" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/config/system", "host": [ "{{base_url}}{{api_prefix}}/blueprints/config/system" ] }, "description": "Get the blueprint for system configuration." }, "response": [] }, { "name": "Get User Blueprint", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/users", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "blueprints", "users" ] }, "description": "Get the user account form blueprint." } }, { "name": "Get Permissions Tree", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/users/permissions", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "blueprints", "users", "permissions" ] }, "description": "Get all registered permission actions as a nested tree." } }, { "name": "Get Plugin Page Blueprint", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has fields', () => pm.expect(pm.response.json().data.fields).to.be.an('array'));", "pm.test('Has name', () => pm.expect(pm.response.json().data).to.have.property('name'));" ] } } ], "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/blueprints/plugins/api/pages/settings", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "blueprints", "plugins", "api", "pages", "settings" ] }, "description": "Get the resolved blueprint for a plugin's custom admin page. Used to render blueprint-form type pages registered by plugins." }, "response": [] }, { "name": "Resolve Data Options", "request": { "method": "GET", "header": [ { "key": "X-API-Key", "value": "{{api_key}}" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Accept", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/data/resolve", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "data", "resolve" ] }, "description": "Resolve a blueprint data-options@ directive. Pass ?callable=\\\\Grav\\\\Common\\\\Page\\\\Pages::pageTypes" } } ] }, { "name": "Translations", "item": [ { "name": "Get All Translations (English)", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('Has lang', () => pm.expect(pm.response.json().data.lang).to.equal('en'));", "pm.test('Has strings object', () => pm.expect(pm.response.json().data.strings).to.be.an('object'));", "pm.test('Has checksum', () => pm.expect(pm.response.json().data.checksum).to.be.a('string'));", "pm.test('Count matches', () => {", " const data = pm.response.json().data;", " pm.expect(data.count).to.equal(Object.keys(data.strings).length);", "});" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "GET", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/translations/en", "host": [ "{{base_url}}{{api_prefix}}/translations/en" ] }, "description": "Get all translation strings for English. No authentication required." }, "response": [] }, { "name": "Get Translations with Prefix Filter", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status is 200', () => pm.response.to.have.status(200));", "pm.test('All keys have prefix', () => {", " const strings = pm.response.json().data.strings;", " Object.keys(strings).forEach(key => {", " pm.expect(key.toUpperCase()).to.match(/^PLUGIN_ADMIN\\./);", " });", "});" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "GET", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/translations/en?prefix=PLUGIN_ADMIN", "host": [ "{{base_url}}{{api_prefix}}/translations/en?prefix=PLUGIN_ADMIN" ] }, "description": "Get translation strings filtered by PLUGIN_ADMIN prefix. Useful for partial/incremental loading." }, "response": [] } ] }, { "name": "Teardown", "description": "Teardown requests that run after all other tests. Cleans up test data.", "item": [ { "name": "Teardown: Delete Test Page", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test(\"Status is 204 or 404\", () => {", " pm.expect(pm.response.code).to.be.oneOf([204, 404]);", "});" ] } } ], "request": { "method": "DELETE", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/pages/newman-test-page?children=true", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "pages", "test", "newman-page" ], "query": [ { "key": "children", "value": "true" } ] }, "description": "Delete the test page created during setup." } }, { "name": "Teardown: Delete Test Webhook", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test(\"Status is 204 or 404\", () => {", " pm.expect(pm.response.code).to.be.oneOf([204, 404]);", "});" ] } } ], "request": { "method": "DELETE", "header": [ { "key": "X-API-Key", "value": "{{api_key}}", "description": "API Key authentication" }, { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" } ], "url": { "raw": "{{base_url}}{{api_prefix}}/webhooks/{{webhook_id}}", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "webhooks", "{{webhook_id}}" ] }, "description": "Delete the test webhook created during setup." } }, { "name": "Teardown: Revoke Token", "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test(\"Status is 204 or 401\", () => {", " pm.expect(pm.response.code).to.be.oneOf([204, 401]);", "});" ] } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "X-Grav-Environment", "value": "{{grav_environment}}", "description": "Grav environment" }, { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"refresh_token\": \"{{refresh_token}}\"\n}" }, "url": { "raw": "{{base_url}}{{api_prefix}}/auth/revoke", "host": [ "{{base_url}}{{api_prefix}}" ], "path": [ "auth", "revoke" ] }, "description": "Revoke the refresh token obtained during setup." } } ] } ] }