diff --git a/docs/api/flowfi.hoppscotch_collection.json b/docs/api/flowfi.hoppscotch_collection.json index a49e9c7..946b315 100644 --- a/docs/api/flowfi.hoppscotch_collection.json +++ b/docs/api/flowfi.hoppscotch_collection.json @@ -36,6 +36,34 @@ "auth": { "authType": "inherit", "authActive": true }, "body": { "contentType": null, "body": null }, "requestVariables": [] + }, + { + "v": "1", + "id": "f6a7b8c9-d0e1-2345-fabc-345678901236", + "name": "Swagger UI", + "method": "GET", + "endpoint": "<>/api-docs", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "f6a7b8c9-d0e1-2345-fabc-345678901237", + "name": "OpenAPI JSON spec", + "method": "GET", + "endpoint": "<>/api-docs.json", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] } ] }, @@ -50,7 +78,7 @@ "id": "b8c9d0e1-f2a3-4567-bcde-567890123457", "name": "Create stream", "method": "POST", - "endpoint": "<>/streams", + "endpoint": "<>/v1/streams", "params": [], "headers": [ { "key": "Content-Type", "value": "application/json", "active": true } @@ -63,13 +91,145 @@ "body": "{\n \"sender\": \"<>\",\n \"recipient\": \"<>\",\n \"amount\": 10000,\n \"token\": \"<>\",\n \"startTime\": 1708531200,\n \"endTime\": 1711209600\n}" }, "requestVariables": [] + }, + { + "v": "1", + "id": "b8c9d0e1-f2a3-4567-bcde-567890123458", + "name": "List streams", + "method": "GET", + "endpoint": "<>/v1/streams", + "params": [ + { "key": "sender", "value": "<>", "active": true }, + { "key": "recipient", "value": "<>", "active": false } + ], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "b8c9d0e1-f2a3-4567-bcde-567890123459", + "name": "Get stream by ID", + "method": "GET", + "endpoint": "<>/v1/streams/<>", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "b8c9d0e1-f2a3-4567-bcde-567890123460", + "name": "Get stream events", + "method": "GET", + "endpoint": "<>/v1/streams/<>/events", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "b8c9d0e1-f2a3-4567-bcde-567890123461", + "name": "Get claimable amount", + "method": "GET", + "endpoint": "<>/v1/streams/<>/claimable", + "params": [ + { "key": "at", "value": "", "active": false } + ], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + } + ] + }, + { + "v": 1, + "id": "a7b8c9d0-e1f2-3456-abcd-456789012347", + "name": "Users", + "folders": [], + "requests": [ + { + "v": "1", + "id": "c9d0e1f2-a3b4-5678-cdef-678901234570", + "name": "Register wallet", + "method": "POST", + "endpoint": "<>/v1/users", + "params": [], + "headers": [ + { "key": "Content-Type", "value": "application/json", "active": true } + ], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { + "contentType": "application/json", + "body": "{\n \"publicKey\": \"<>\"\n}" + }, + "requestVariables": [] + }, + { + "v": "1", + "id": "c9d0e1f2-a3b4-5678-cdef-678901234571", + "name": "Get user by public key", + "method": "GET", + "endpoint": "<>/v1/users/<>", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "c9d0e1f2-a3b4-5678-cdef-678901234572", + "name": "Get current user (authenticated)", + "method": "GET", + "endpoint": "<>/v1/users/me", + "params": [], + "headers": [ + { "key": "Authorization", "value": "Bearer <>", "active": true } + ], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] + }, + { + "v": "1", + "id": "c9d0e1f2-a3b4-5678-cdef-678901234573", + "name": "Get user activity events", + "method": "GET", + "endpoint": "<>/v1/users/<>/events", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { "authType": "inherit", "authActive": true }, + "body": { "contentType": null, "body": null }, + "requestVariables": [] } ] }, { "v": 1, "id": "c9d0e1f2-a3b4-5678-cdef-678901234568", - "name": "Events", + "name": "Events (SSE)", "folders": [], "requests": [ { @@ -77,9 +237,9 @@ "id": "d0e1f2a3-b4c5-6789-defa-789012345679", "name": "Subscribe to stream events (SSE)", "method": "GET", - "endpoint": "<>/events/subscribe", + "endpoint": "<>/v1/events/subscribe", "params": [ - { "key": "streams", "value": "123", "active": true }, + { "key": "streams", "value": "<>", "active": true }, { "key": "users", "value": "<>", "active": true }, { "key": "all", "value": "false", "active": true } ], @@ -98,7 +258,7 @@ "id": "e1f2a3b4-c5d6-7890-efab-890123456780", "name": "Get SSE connection stats", "method": "GET", - "endpoint": "<>/events/stats", + "endpoint": "<>/v1/events/stats", "params": [], "headers": [], "preRequestScript": "", diff --git a/docs/api/flowfi.postman_collection.json b/docs/api/flowfi.postman_collection.json index b25b80c..6a180da 100644 --- a/docs/api/flowfi.postman_collection.json +++ b/docs/api/flowfi.postman_collection.json @@ -2,7 +2,7 @@ "info": { "_postman_id": "7f3e2a1b-4c5d-6e7f-8a9b-0c1d2e3f4a5b", "name": "FlowFi API", - "description": "Complete API collection for FlowFi — real-time payment streaming on Stellar.\n\n**Before you start:**\n1. Import one of the environment files from the same folder:\n - `local.postman_environment.json` — Docker / manual local setup (port 3001)\n - `test.postman_environment.json` — shared test deployment\n2. Select the imported environment from the top-right dropdown.\n3. Send requests. Variables like `{{baseUrl}}`, `{{senderPublicKey}}`, etc. are resolved automatically.\n\n**Swagger UI** (local): http://localhost:3001/api-docs\n**OpenAPI JSON** (local): http://localhost:3001/api-docs.json", + "description": "Complete API collection for FlowFi — real-time payment streaming on Stellar.\n\n**Before you start:**\n1. Import one of the environment files from the same folder:\n - `local.postman_environment.json` — Docker / manual local setup (port 3001)\n - `test.postman_environment.json` — shared test deployment\n2. Select the imported environment from the top-right dropdown.\n3. Send requests. Variables like `{{baseUrl}}`, `{{senderPublicKey}}`, etc. are resolved automatically.\n\n**Sandbox mode:** Add `X-Sandbox-Mode: true` header or `?sandbox=true` to any request.\n**Swagger UI** (local): http://localhost:3001/api-docs\n**OpenAPI JSON** (local): http://localhost:3001/api-docs.json", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "variable": [ @@ -33,21 +33,10 @@ "response": [ { "name": "200 OK", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/", - "host": ["{{baseUrl}}"], - "path": [""] - } - }, "status": "OK", "code": 200, "_postman_previewlanguage": "plain", - "header": [ - { "key": "Content-Type", "value": "text/plain; charset=utf-8" } - ], + "header": [{ "key": "Content-Type", "value": "text/plain; charset=utf-8" }], "body": "FlowFi Backend is running" } ] @@ -62,114 +51,322 @@ "host": ["{{baseUrl}}"], "path": ["health"] }, - "description": "Returns a JSON object with `status`, `timestamp`, `uptime` (seconds), and `version`. Use this before running integration tests to confirm the API is healthy." + "description": "Returns status, uptime, version, supported API versions, and service health." }, "response": [ { "name": "200 OK", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/health", - "host": ["{{baseUrl}}"], - "path": ["health"] - } - }, "status": "OK", "code": 200, "_postman_previewlanguage": "json", - "header": [ - { "key": "Content-Type", "value": "application/json; charset=utf-8" } - ], - "body": "{\n \"status\": \"healthy\",\n \"timestamp\": \"2024-02-21T14:30:00.000Z\",\n \"uptime\": 3600,\n \"version\": \"1.0.0\"\n}" + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"status\": \"healthy\",\n \"timestamp\": \"2024-02-21T14:30:00.000Z\",\n \"uptime\": 3600,\n \"version\": \"1.0.0\",\n \"api\": {\n \"supported\": [\"v1\"],\n \"default\": \"v1\"\n }\n}" } ] + }, + { + "name": "Swagger UI", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api-docs", + "host": ["{{baseUrl}}"], + "path": ["api-docs"] + }, + "description": "Interactive Swagger UI for the FlowFi API. Open in a browser." + }, + "response": [] + }, + { + "name": "OpenAPI JSON spec", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api-docs.json", + "host": ["{{baseUrl}}"], + "path": ["api-docs.json"] + }, + "description": "Raw OpenAPI 3.0 specification in JSON format." + }, + "response": [] } ] }, { "name": "Streams", - "description": "Payment stream lifecycle management.", + "description": "Payment stream lifecycle management. All endpoints prefixed with `/v1/streams`.", "item": [ { "name": "Create stream", "request": { "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], + "header": [{ "key": "Content-Type", "value": "application/json" }], "body": { "mode": "raw", "raw": "{\n \"sender\": \"{{senderPublicKey}}\",\n \"recipient\": \"{{recipientPublicKey}}\",\n \"amount\": 10000,\n \"token\": \"{{tokenAddress}}\",\n \"startTime\": 1708531200,\n \"endTime\": 1711209600\n}", - "options": { - "raw": { "language": "json" } - } + "options": { "raw": { "language": "json" } } }, "url": { - "raw": "{{baseUrl}}/streams", + "raw": "{{baseUrl}}/v1/streams", "host": ["{{baseUrl}}"], - "path": ["streams"] + "path": ["v1", "streams"] }, - "description": "Creates a new payment stream.\n\n**Required fields:** `sender`, `recipient`, `amount` (positive number), `token`.\n**Optional fields:** `startTime`, `endTime` (Unix timestamps).\n\nOn success the server responds with **201 Created** and the new stream object, then broadcasts a `stream.created` SSE event to all subscribers watching the sender, recipient, or stream ID.\n\nValidation is enforced by Zod; invalid payloads return **400** with a structured `errors` array." + "description": "Creates a new payment stream.\n\n**Required:** `sender`, `recipient`, `amount` (positive), `token`.\n**Optional:** `startTime`, `endTime` (Unix timestamps).\n\nReturns **201 Created** with the stream object. Broadcasts `stream.created` SSE event." }, "response": [ { "name": "201 Created", - "originalRequest": { - "method": "POST", - "header": [{ "key": "Content-Type", "value": "application/json" }], - "body": { - "mode": "raw", - "raw": "{\n \"sender\": \"GABC123XYZ456DEF789GHI012JKL345MNO678PQR901STU234VWX567YZA\",\n \"recipient\": \"GDEF456ABC789GHI012JKL345MNO678PQR901STU234VWX567YZA123BCD\",\n \"amount\": 10000,\n \"token\": \"CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE\",\n \"startTime\": 1708531200,\n \"endTime\": 1711209600\n}" - }, - "url": { - "raw": "{{baseUrl}}/streams", - "host": ["{{baseUrl}}"], - "path": ["streams"] - } - }, "status": "Created", "code": 201, "_postman_previewlanguage": "json", - "header": [ - { "key": "Content-Type", "value": "application/json; charset=utf-8" } - ], - "body": "{\n \"id\": \"123\",\n \"status\": \"pending\",\n \"sender\": \"GABC123XYZ456DEF789GHI012JKL345MNO678PQR901STU234VWX567YZA\",\n \"recipient\": \"GDEF456ABC789GHI012JKL345MNO678PQR901STU234VWX567YZA123BCD\",\n \"amount\": 10000,\n \"token\": \"CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE\",\n \"startTime\": 1708531200,\n \"endTime\": 1711209600\n}" + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"id\": \"uuid\",\n \"streamId\": 1,\n \"sender\": \"GABC...\",\n \"recipient\": \"GDEF...\",\n \"tokenAddress\": \"CBCD...\",\n \"depositedAmount\": \"10000\",\n \"isActive\": true,\n \"startTime\": 1708531200,\n \"createdAt\": \"2024-02-21T14:30:00.000Z\"\n}" }, { "name": "400 Validation error", - "originalRequest": { - "method": "POST", - "header": [{ "key": "Content-Type", "value": "application/json" }], - "body": { - "mode": "raw", - "raw": "{\n \"sender\": \"\",\n \"recipient\": \"GDEF456ABC789GHI012JKL345MNO678PQR901STU234VWX567YZA123BCD\",\n \"amount\": -5,\n \"token\": \"CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/streams", - "host": ["{{baseUrl}}"], - "path": ["streams"] - } - }, "status": "Bad Request", "code": 400, "_postman_previewlanguage": "json", - "header": [ - { "key": "Content-Type", "value": "application/json; charset=utf-8" } - ], - "body": "{\n \"message\": \"Validation failed\",\n \"errors\": [\n {\n \"code\": \"too_small\",\n \"path\": [\"sender\"],\n \"message\": \"Sender address is required\"\n },\n {\n \"code\": \"too_small\",\n \"path\": [\"amount\"],\n \"message\": \"Amount must be positive\"\n }\n ]\n}" + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"message\": \"Validation failed\",\n \"errors\": [\n { \"code\": \"too_small\", \"path\": [\"sender\"], \"message\": \"Sender address is required\" }\n ]\n}" + } + ] + }, + { + "name": "List streams", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/streams?sender={{senderPublicKey}}&recipient={{recipientPublicKey}}", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams"], + "query": [ + { "key": "sender", "value": "{{senderPublicKey}}", "description": "Filter by sender address (optional)." }, + { "key": "recipient", "value": "{{recipientPublicKey}}", "description": "Filter by recipient address (optional).", "disabled": true } + ] + }, + "description": "List all streams, optionally filtered by sender and/or recipient public key." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "[\n {\n \"streamId\": 1,\n \"sender\": \"GABC...\",\n \"recipient\": \"GDEF...\",\n \"isActive\": true\n }\n]" + } + ] + }, + { + "name": "Get stream by ID", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}"] + }, + "description": "Get details for a single stream including related events." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"streamId\": 1,\n \"sender\": \"GABC...\",\n \"recipient\": \"GDEF...\",\n \"tokenAddress\": \"CBCD...\",\n \"ratePerSecond\": \"115740\",\n \"depositedAmount\": \"10000\",\n \"withdrawnAmount\": \"0\",\n \"startTime\": 1708531200,\n \"lastUpdateTime\": 1708531200,\n \"isActive\": true,\n \"events\": []\n}" + }, + { + "name": "404 Not Found", + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"message\": \"Stream not found\"\n}" + } + ] + }, + { + "name": "Get stream events", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/events", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "events"] + }, + "description": "Get all indexed on-chain events for a stream (CREATED, TOPPED_UP, WITHDRAWN, CANCELLED, COMPLETED)." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "[\n {\n \"id\": \"uuid\",\n \"streamId\": 1,\n \"eventType\": \"CREATED\",\n \"transactionHash\": \"abc123...\",\n \"ledgerSequence\": 12345,\n \"timestamp\": 1708531200\n }\n]" + } + ] + }, + { + "name": "Get claimable amount", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/streams/{{streamId}}/claimable", + "host": ["{{baseUrl}}"], + "path": ["v1", "streams", "{{streamId}}", "claimable"], + "query": [ + { "key": "at", "value": "", "description": "Optional Unix timestamp to calculate claimable at a specific time.", "disabled": true } + ] + }, + "description": "Calculate the actionable claimable amount for a stream. Supports caching." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"streamId\": 1,\n \"claimableAmount\": \"5000\",\n \"actionable\": true,\n \"calculatedAt\": \"2024-02-21T14:30:00.000Z\",\n \"cached\": false\n}" + } + ] + } + ] + }, + { + "name": "Users", + "description": "User registration and profile endpoints. All prefixed with `/v1/users`.", + "item": [ + { + "name": "Register wallet", + "request": { + "method": "POST", + "header": [{ "key": "Content-Type", "value": "application/json" }], + "body": { + "mode": "raw", + "raw": "{\n \"publicKey\": \"{{senderPublicKey}}\"\n}", + "options": { "raw": { "language": "json" } } + }, + "url": { + "raw": "{{baseUrl}}/v1/users", + "host": ["{{baseUrl}}"], + "path": ["v1", "users"] + }, + "description": "Register a Stellar wallet public key. Returns 201 for new users or 200 if the key already exists." + }, + "response": [ + { + "name": "201 Created", + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"id\": \"uuid\",\n \"publicKey\": \"GABC...\",\n \"createdAt\": \"2024-02-21T14:30:00.000Z\",\n \"updatedAt\": \"2024-02-21T14:30:00.000Z\"\n}" + } + ] + }, + { + "name": "Get user by public key", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/users/{{senderPublicKey}}", + "host": ["{{baseUrl}}"], + "path": ["v1", "users", "{{senderPublicKey}}"] + }, + "description": "Get a user profile by Stellar public key, including their recent sent and received streams." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"id\": \"uuid\",\n \"publicKey\": \"GABC...\",\n \"sentStreams\": [],\n \"receivedStreams\": []\n}" + }, + { + "name": "404 Not Found", + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"message\": \"User not found\"\n}" + } + ] + }, + { + "name": "Get current user (authenticated)", + "request": { + "method": "GET", + "header": [ + { "key": "Authorization", "value": "Bearer {{authToken}}", "description": "Signed Stellar transaction XDR (SEP-10)." } + ], + "url": { + "raw": "{{baseUrl}}/v1/users/me", + "host": ["{{baseUrl}}"], + "path": ["v1", "users", "me"] + }, + "description": "Returns the authenticated user based on the signed Stellar transaction in the Authorization header (SEP-10 auth)." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"id\": \"uuid\",\n \"publicKey\": \"GABC...\"\n}" + }, + { + "name": "401 Unauthorized", + "status": "Unauthorized", + "code": 401, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"message\": \"Unauthorized\"\n}" + } + ] + }, + { + "name": "Get user activity events", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/v1/users/{{senderPublicKey}}/events", + "host": ["{{baseUrl}}"], + "path": ["v1", "users", "{{senderPublicKey}}", "events"] + }, + "description": "Get all stream events associated with a user (as sender or recipient)." + }, + "response": [ + { + "name": "200 OK", + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "[\n {\n \"id\": \"uuid\",\n \"streamId\": 1,\n \"eventType\": \"CREATED\",\n \"timestamp\": 1708531200\n }\n]" } ] } ] }, { - "name": "Events", - "description": "Server-Sent Events (SSE) for real-time stream updates and connection monitoring.", + "name": "Events (SSE)", + "description": "Server-Sent Events for real-time stream updates. All prefixed with `/v1/events`.", "item": [ { "name": "Subscribe to stream events (SSE)", @@ -180,45 +377,20 @@ { "key": "Cache-Control", "value": "no-cache" } ], "url": { - "raw": "{{baseUrl}}/events/subscribe?streams=123&users={{senderPublicKey}}&all=false", + "raw": "{{baseUrl}}/v1/events/subscribe?streams={{streamId}}&users={{senderPublicKey}}&all=false", "host": ["{{baseUrl}}"], - "path": ["events", "subscribe"], + "path": ["v1", "events", "subscribe"], "query": [ - { - "key": "streams", - "value": "123", - "description": "Stream ID to watch. Repeat the key for multiple IDs: streams=1&streams=2" - }, - { - "key": "users", - "value": "{{senderPublicKey}}", - "description": "Stellar public key to watch. Repeat the key for multiple keys." - }, - { - "key": "all", - "value": "false", - "description": "Set to true to receive every event regardless of stream or user filter." - } + { "key": "streams", "value": "{{streamId}}", "description": "Stream ID to watch. Repeat for multiple." }, + { "key": "users", "value": "{{senderPublicKey}}", "description": "Public key to watch. Repeat for multiple." }, + { "key": "all", "value": "false", "description": "Set to true to receive all events." } ] }, - "description": "Establishes a persistent Server-Sent Events connection. The server pushes newline-delimited `text/event-stream` data for the following event types:\n\n| Event | Description |\n|---|---|\n| `stream.created` | New stream created |\n| `stream.topped_up` | Additional funds deposited |\n| `stream.withdrawn` | Funds withdrawn |\n| `stream.cancelled` | Stream cancelled |\n| `stream.completed` | Stream finished |\n\nUse **at least one** filter: `streams`, `users`, or `all=true`. The server immediately sends a `connected` event with a `clientId` on handshake.\n\n**Postman note:** Postman buffers SSE. Use *Send and Download* or watch the raw response body. For interactive testing, open `backend/test-sse-client.html` in a browser or run:\n```\ncurl -N --no-buffer 'http://localhost:3001/events/subscribe?all=true'\n```" + "description": "Establishes a persistent SSE connection. Pushes events: `stream.created`, `stream.topped_up`, `stream.withdrawn`, `stream.cancelled`, `stream.completed`.\n\nUse at least one filter: `streams`, `users`, or `all=true`.\n\n**Postman note:** SSE is buffered. Use *Send and Download*, or test with:\n```\ncurl -N --no-buffer '{{baseUrl}}/v1/events/subscribe?all=true'\n```" }, "response": [ { - "name": "200 SSE stream (handshake + event example)", - "originalRequest": { - "method": "GET", - "header": [ - { "key": "Accept", "value": "text/event-stream" }, - { "key": "Cache-Control", "value": "no-cache" } - ], - "url": { - "raw": "{{baseUrl}}/events/subscribe?all=true", - "host": ["{{baseUrl}}"], - "path": ["events", "subscribe"], - "query": [{ "key": "all", "value": "true" }] - } - }, + "name": "200 SSE stream", "status": "OK", "code": 200, "_postman_previewlanguage": "text", @@ -227,29 +399,15 @@ { "key": "Cache-Control", "value": "no-cache" }, { "key": "Connection", "value": "keep-alive" } ], - "body": "data: {\"type\":\"connected\",\"clientId\":\"1708531200-abc123xyz\"}\n\nevent: stream.created\ndata: {\"id\":\"123\",\"status\":\"pending\",\"sender\":\"GABC123XYZ456DEF789GHI012JKL345MNO678PQR901STU234VWX567YZA\",\"recipient\":\"GDEF456ABC789GHI012JKL345MNO678PQR901STU234VWX567YZA123BCD\",\"amount\":10000,\"token\":\"CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE\"}\n\n" + "body": "data: {\"type\":\"connected\",\"clientId\":\"1708531200-abc123xyz\"}\n\nevent: stream.created\ndata: {\"streamId\":1,\"sender\":\"GABC...\",\"recipient\":\"GDEF...\",\"amount\":10000}\n\n" }, { - "name": "400 Invalid subscription parameters", - "originalRequest": { - "method": "GET", - "header": [ - { "key": "Accept", "value": "text/event-stream" }, - { "key": "Cache-Control", "value": "no-cache" } - ], - "url": { - "raw": "{{baseUrl}}/events/subscribe", - "host": ["{{baseUrl}}"], - "path": ["events", "subscribe"] - } - }, + "name": "400 Missing filter", "status": "Bad Request", "code": 400, "_postman_previewlanguage": "json", - "header": [ - { "key": "Content-Type", "value": "application/json; charset=utf-8" } - ], - "body": "{\n \"message\": \"Invalid subscription parameters\",\n \"errors\": [\n {\n \"code\": \"invalid_type\",\n \"path\": [\"all\"],\n \"message\": \"Expected boolean, received string\"\n }\n ]\n}" + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], + "body": "{\n \"message\": \"Invalid subscription parameters\"\n}" } ] }, @@ -259,30 +417,19 @@ "method": "GET", "header": [], "url": { - "raw": "{{baseUrl}}/events/stats", + "raw": "{{baseUrl}}/v1/events/stats", "host": ["{{baseUrl}}"], - "path": ["events", "stats"] + "path": ["v1", "events", "stats"] }, - "description": "Returns the current count of active SSE connections and a server timestamp. Useful for connection health monitoring and load assessment." + "description": "Returns the count of active SSE connections and server timestamp." }, "response": [ { "name": "200 OK", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/events/stats", - "host": ["{{baseUrl}}"], - "path": ["events", "stats"] - } - }, "status": "OK", "code": 200, "_postman_previewlanguage": "json", - "header": [ - { "key": "Content-Type", "value": "application/json; charset=utf-8" } - ], + "header": [{ "key": "Content-Type", "value": "application/json; charset=utf-8" }], "body": "{\n \"activeConnections\": 3,\n \"timestamp\": \"2024-02-21T14:30:00.000Z\"\n}" } ] diff --git a/docs/api/local.hoppscotch_environment.json b/docs/api/local.hoppscotch_environment.json index 115b3fb..e9177cc 100644 --- a/docs/api/local.hoppscotch_environment.json +++ b/docs/api/local.hoppscotch_environment.json @@ -22,6 +22,16 @@ "key": "tokenAddress", "value": "CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE", "secret": false + }, + { + "key": "streamId", + "value": "1", + "secret": false + }, + { + "key": "authToken", + "value": "", + "secret": true } ] } diff --git a/docs/api/local.postman_environment.json b/docs/api/local.postman_environment.json index 51d44d2..d5688ad 100644 --- a/docs/api/local.postman_environment.json +++ b/docs/api/local.postman_environment.json @@ -29,6 +29,20 @@ "type": "default", "enabled": true, "description": "Example Soroban token contract address. Replace with a deployed testnet token." + }, + { + "key": "streamId", + "value": "1", + "type": "default", + "enabled": true, + "description": "Example stream ID for GET requests. Replace with an actual stream ID after creating one." + }, + { + "key": "authToken", + "value": "", + "type": "default", + "enabled": true, + "description": "Signed Stellar transaction XDR for SEP-10 auth. Required for GET /v1/users/me." } ], "_postman_variable_scope": "environment", diff --git a/docs/api/test.hoppscotch_environment.json b/docs/api/test.hoppscotch_environment.json index b50fbff..26e5e5f 100644 --- a/docs/api/test.hoppscotch_environment.json +++ b/docs/api/test.hoppscotch_environment.json @@ -22,6 +22,16 @@ "key": "tokenAddress", "value": "CBCD789EFG012HIJ345KLM678NOP901QRS234TUV567WXY890ZAB123CDE", "secret": false + }, + { + "key": "streamId", + "value": "1", + "secret": false + }, + { + "key": "authToken", + "value": "", + "secret": true } ] } diff --git a/docs/api/test.postman_environment.json b/docs/api/test.postman_environment.json index b124b28..2b432d0 100644 --- a/docs/api/test.postman_environment.json +++ b/docs/api/test.postman_environment.json @@ -29,6 +29,20 @@ "type": "default", "enabled": true, "description": "Testnet Soroban token contract address." + }, + { + "key": "streamId", + "value": "1", + "type": "default", + "enabled": true, + "description": "Example stream ID for GET requests." + }, + { + "key": "authToken", + "value": "", + "type": "default", + "enabled": true, + "description": "Signed Stellar transaction XDR for SEP-10 auth." } ], "_postman_variable_scope": "environment",