{ "info": { "_postman_id": "95186b61-1197-4a6e-a90f-d97223528d90", "name": "LetsEncrypt Client (MaksIT.Webapi)", "description": "Aligned with MaksIT.Webapi controllers: routes under /api (except /.well-known/acme-challenge). Use Identity Login first, then set collection variable accessToken from the response (tests on Login do this). JWT is required for all /api/* routes except identity login, refresh, and logout.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{accessToken}}", "type": "string" } ] }, "variable": [ { "key": "baseUrl", "value": "http://localhost:8080" }, { "key": "accessToken", "value": "" }, { "key": "refreshToken", "value": "" }, { "key": "sessionId", "value": "" }, { "key": "accountId", "value": "" }, { "key": "userId", "value": "" }, { "key": "challenge", "value": "" }, { "key": "isStaging", "value": "true" }, { "key": "letsEncryptDirectory", "value": "https://acme-v02.api.letsencrypt.org/directory" } ], "item": [ { "name": "Identity", "item": [ { "name": "login", "event": [ { "listen": "test", "script": { "exec": [ "if (pm.response.code === 200) {", " const j = pm.response.json();", " const token = j.token ?? j.Token;", " const refresh = j.refreshToken ?? j.RefreshToken;", " if (token) pm.collectionVariables.set('accessToken', token);", " if (refresh) pm.collectionVariables.set('refreshToken', refresh);", "}" ], "type": "text/javascript" } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"username\": \"admin\",\n \"password\": \"password\"\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/identity/login" } }, { "name": "refresh", "event": [ { "listen": "test", "script": { "exec": [ "if (pm.response.code === 200) {", " const j = pm.response.json();", " const token = j.token ?? j.Token;", " if (token) pm.collectionVariables.set('accessToken', token);", "}" ], "type": "text/javascript" } } ], "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"refreshToken\": \"{{refreshToken}}\"\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/identity/refresh" } }, { "name": "logout", "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"token\": \"{{accessToken}}\",\n \"logoutFromAllDevices\": false\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/identity/logout" } }, { "name": "patch user (password)", "request": { "method": "PATCH", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"password\": \"new-password\",\n \"operations\": {\n \"password\": \"SetField\"\n }\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/identity/user/{{userId}}" } } ] }, { "name": "Accounts", "item": [ { "name": "list accounts", "request": { "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }], "url": "{{baseUrl}}/api/accounts" } }, { "name": "get account", "request": { "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }], "url": "{{baseUrl}}/api/account/{{accountId}}" } }, { "name": "create account (full flow)", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"description\": \"Postman test\",\n \"contacts\": [\"mailto:you@example.com\"],\n \"challengeType\": \"http-01\",\n \"hostnames\": [\"staging.example.com\"],\n \"isStaging\": true,\n \"agreeToS\": true\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/account" } }, { "name": "patch account (description)", "request": { "method": "PATCH", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"description\": \"Updated from Postman\",\n \"operations\": {\n \"description\": \"SetField\"\n }\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/account/{{accountId}}" } }, { "name": "delete account", "request": { "method": "DELETE", "header": [{ "key": "Accept", "value": "application/json" }], "url": "{{baseUrl}}/api/account/{{accountId}}" } } ] }, { "name": "Cache", "item": [ { "name": "download full cache (zip)", "request": { "method": "GET", "url": "{{baseUrl}}/api/cache/download" } }, { "name": "upload full cache (zip)", "request": { "method": "POST", "body": { "mode": "formdata", "formdata": [ { "key": "file", "type": "file", "src": [] } ] }, "url": "{{baseUrl}}/api/cache/upload" } }, { "name": "delete full cache", "request": { "method": "DELETE", "url": "{{baseUrl}}/api/cache" } }, { "name": "download account cache (zip)", "request": { "method": "GET", "url": "{{baseUrl}}/api/cache/{{accountId}}/download" } }, { "name": "upload account cache (zip bytes)", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "\"\"", "options": { "raw": { "language": "json" } } }, "description": "API binds [FromBody] byte[] as a base64 JSON string. Replace with a real base64 zip payload.", "url": "{{baseUrl}}/api/cache/{{accountId}}/upload" } } ] }, { "name": "Certs flow", "item": [ { "name": "letsencrypt directory (external)", "request": { "auth": { "type": "noauth" }, "method": "GET", "header": [], "url": "{{letsEncryptDirectory}}", "description": "Public ACME directory URL (status: https://letsencrypt.status.io/)" } }, { "name": "configure-client", "event": [ { "listen": "test", "script": { "exec": [ "if (pm.response.code !== 200) return;", "let id = null;", "try {", " const j = pm.response.json();", " if (typeof j === 'string') id = j.replace(/^\"|\"$/g, '');", " else if (j && j.value != null) id = String(j.value);", " else if (j && j.sessionId) id = String(j.sessionId);", "} catch (e) {", " const m = pm.response.text().match(/[0-9a-fA-F]{8}-[0-9a-fA-F-]{27}/);", " if (m) id = m[0];", "}", "if (id && /^[0-9a-fA-F-]{36}$/.test(id)) {", " pm.collectionVariables.set('sessionId', id);", " console.log('sessionId set to', id);", "}" ], "type": "text/javascript" } } ], "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"isStaging\": {{isStaging}}\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/configure-client" } }, { "name": "terms-of-service", "request": { "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }], "url": "{{baseUrl}}/api/certs/{{sessionId}}/terms-of-service", "description": "Returns base64-encoded PDF (JSON string or wrapped per API Result serializer)." } }, { "name": "init (new account)", "event": [ { "listen": "test", "script": { "exec": [ "if (pm.response.code !== 200) return;", "try {", " const j = pm.response.json();", " const v = typeof j === 'string' ? j.replace(/^\"|\"$/g, '') : (j.value != null ? String(j.value) : null);", " if (v && /^[0-9a-fA-F-]{36}$/.test(v)) pm.collectionVariables.set('accountId', v);", "} catch (e) {}" ], "type": "text/javascript" } } ], "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"description\": \"Postman session\",\n \"contacts\": [\"mailto:you@example.com\"]\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/{{sessionId}}/init" } }, { "name": "init (existing account)", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"description\": \"Postman session\",\n \"contacts\": [\"mailto:you@example.com\"]\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/{{sessionId}}/init/{{accountId}}" } }, { "name": "new order", "event": [ { "listen": "test", "script": { "exec": [ "if (pm.response.code !== 200) return;", "const j = pm.response.json();", "const arr = Array.isArray(j) ? j : (j.value && Array.isArray(j.value) ? j.value : null);", "if (arr && arr.length > 0) {", " pm.collectionVariables.set('challenge', arr[0]);", " console.log('challenge token file name:', arr[0]);", "}" ], "type": "text/javascript" } } ], "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"hostnames\": [\"staging.example.com\"],\n \"challengeType\": \"http-01\"\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/{{sessionId}}/order" } }, { "name": "acme-challenge (local API)", "request": { "auth": { "type": "noauth" }, "method": "GET", "url": "{{baseUrl}}/.well-known/acme-challenge/{{challenge}}", "description": "No JWT. Returns text/plain challenge response." } }, { "name": "acme-challenge (public host)", "request": { "auth": { "type": "noauth" }, "method": "GET", "url": "http://staging.example.com/.well-known/acme-challenge/{{challenge}}" } }, { "name": "complete-challenges", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "url": "{{baseUrl}}/api/certs/{{sessionId}}/complete-challenges" } }, { "name": "order-status", "request": { "method": "GET", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"hostnames\": [\"staging.example.com\"]\n}", "options": { "raw": { "language": "json" } } }, "description": "Matches CertsFlowController: HttpGet with [FromBody] GetOrderRequest. Some clients/proxies strip GET bodies; if this fails, consider fixing the API to POST.", "url": "{{baseUrl}}/api/certs/{{sessionId}}/order-status" } }, { "name": "download certificates", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"hostnames\": [\"staging.example.com\"]\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/{{sessionId}}/certificates/download" } }, { "name": "apply certificates", "request": { "method": "POST", "header": [ { "key": "Accept", "value": "application/json" } ], "description": "Uses accountId (not sessionId). No request body.", "url": "{{baseUrl}}/api/certs/{{accountId}}/certificates/apply" } }, { "name": "revoke certificates", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Accept", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"hostnames\": [\"staging.example.com\"]\n}", "options": { "raw": { "language": "json" } } }, "url": "{{baseUrl}}/api/certs/{{sessionId}}/certificates/revoke" } } ] }, { "name": "Agent (via Web API)", "description": "Proxied by AgentController; uses same JWT as other /api routes.", "item": [ { "name": "test (HelloWorld)", "request": { "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }], "url": "{{baseUrl}}/api/agent/test" } } ] } ] }