{"id":20172271,"url":"https://github.com/apostoldevel/module-websocketapi","last_synced_at":"2026-05-10T13:04:00.159Z","repository":{"id":110915786,"uuid":"291072126","full_name":"apostoldevel/module-WebSocketAPI","owner":"apostoldevel","description":"Module: Web Socket API","archived":false,"fork":false,"pushed_at":"2024-02-07T17:13:26.000Z","size":158,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-13T15:50:02.052Z","etag":null,"topics":["websocket","websocketapi"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apostoldevel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-28T14:49:42.000Z","updated_at":"2022-01-04T22:06:53.000Z","dependencies_parsed_at":"2024-02-07T18:30:08.900Z","dependency_job_id":"8de7bee8-5c68-49f4-89bb-18503416db42","html_url":"https://github.com/apostoldevel/module-WebSocketAPI","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostoldevel%2Fmodule-WebSocketAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostoldevel%2Fmodule-WebSocketAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostoldevel%2Fmodule-WebSocketAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostoldevel%2Fmodule-WebSocketAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apostoldevel","download_url":"https://codeload.github.com/apostoldevel/module-WebSocketAPI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241607681,"owners_count":19989936,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["websocket","websocketapi"],"created_at":"2024-11-14T01:29:27.679Z","updated_at":"2026-05-10T13:04:00.153Z","avatar_url":"https://github.com/apostoldevel.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![ru](https://img.shields.io/badge/lang-ru-green.svg)](README.ru-RU.md)\n\nWebSocket API\n-\n\n**Module** for **Apostol CRM**[^crm].\n\nDescription\n-\n\n**WebSocket API** provides real-time WebSocket connectivity to the API. It implements a lightweight JSON-based RPC protocol over WebSocket, an event subscription system (Observer pattern), and a REST endpoint for pushing data to connected clients.\n\nDatabase module\n-\n\nWebSocketAPI is tightly coupled to the **`observer`**, **`notification`**, **`notice`**, **`message`**, and **`log`** modules of [db-platform](https://github.com/apostoldevel/db-platform).\n\nThe C++ module handles WebSocket transport and session routing. All subscription state, publisher registration, and event data live entirely in the database:\n\n| db-platform module | Purpose |\n|--------------------|---------|\n| `observer` | Publisher/subscriber registry: stores publishers (`observer.publisher`) and active listener subscriptions (`observer.listener`) per session |\n| `notification` | Source of `notify` publisher events — fires whenever a user interacts with a system object (create/update/delete/transition) |\n| `notice` | Source of `notice` publisher events — system-level notices grouped by category |\n| `message` | Source of `message` publisher events — inbox and outbox message records from the `message` entity |\n| `log` | Source of `log` publisher events — event log entries (M/W/E/D) from the system log |\n\nKey database objects:\n\n| Object | Purpose |\n|--------|---------|\n| `observer.publisher` | Registered publishers (`notify`, `notice`, `message`, `log`, `geo`) |\n| `observer.listener` | Active subscriptions: session → publisher with filter and params |\n| `api.observer_subscribe(publisher, filter, params)` | Creates or updates a listener for the current session |\n| `api.observer_unsubscribe(publisher)` | Removes the listener for the current session |\n| `api.observer_publisher(code)` | Returns publisher metadata |\n| `api.observer_listener(publisher, session)` | Returns listener state for a session |\n\nClient Connection\n-\n\nTo establish a WebSocket connection the client must perform an Opening Handshake as described in [RFC 6455, Section 4](https://tools.ietf.org/html/rfc6455#section-4).\n\nThe server imposes additional constraints on the WebSocket URL, described below.\n\n### Connection URL\n\nThe WebSocket connection is scoped to a previously created session. A session is created after successful user authentication, which yields an access token, a session code, and a secret key.\n\nThe connection URL contains the session code and an optional identity that distinguishes multiple connections within the same session.\n\nURL format:\n\n```\nws[s]://[ws.]example.com/session/\u003ccode\u003e[/\u003cidentity\u003e]\n```\n\nWhere:\n- `\u003ccode\u003e` — **Required.** Session code (40 characters).\n- `\u003cidentity\u003e` — **Optional.** Connection identity within the session. Used to maintain multiple simultaneous connections to the same session.\n\nExamples:\n\n```\nwss://ws.example.com/session/c83b2f85321f95341707624546ca6ac4fa6d1115\n```\n\n```\nwss://ws.example.com/session/c83b2f85321f95341707624546ca6ac4fa6d1115/user1\n```\n\n**Important.** Event subscriptions are bound to the `(session, identity)` pair: the server delivers events to the exact WebSocket connection that created the subscription. When `\u003cidentity\u003e` is present in the URL, calls to `/observer/subscribe` on that connection automatically adopt it, **unless** the payload explicitly sets `identity`. A subscription without an `identity` binding is stored under `identity = \"main\"` and will not reach a connection whose URL carries a different identity. Set `identity` explicitly in the payload to override — the payload value takes precedence.\n\nRPC Protocol\n-\n\nThe WebSocket protocol itself does not provide request/response semantics. To enable this, a small JSON-based RPC protocol is layered on top of WebSocket.\n\n### JSON Frame Fields\n\nKey | Name | Type | Description\n--- | ---- | ---- | -----------\n`t` | MessageTypeId | INTEGER | Message type (see below).\n`u` | UniqueId | UUID | Unique message identifier. When a server message is a reply to a client request, both share the same UniqueId.\n`a` | Action | STRING | API endpoint route.\n`c` | ErrorCode | INTEGER | Error code.\n`m` | ErrorMessage | STRING | Error description.\n`p` | Payload | JSON | Message payload.\n\n### Message Types (MessageTypeId)\n\nType | Number | Direction | Description\n---- | ------ | --------- | -----------\n`OPEN` | 0 | Client → Server | Authorize an existing session.\n`CLOSE` | 1 | Client → Server | Close the session (sign out).\n`CALL` | 2 | Client ↔ Server | Request or server-initiated push.\n`CALLRESULT` | 3 | Server → Client | Successful response to a `CALL`.\n`CALLERROR` | 4 | Server → Client | Error response to a `CALL`.\n\nAuthorization\n-\n\nAfter connecting, the client must authorize before sending API requests.\n\nAuthorization can be performed automatically during the handshake if the following HTTP headers are provided:\n\n```\nAuthorization: Bearer \u003ctoken\u003e\n```\n\nOr:\n\n```\nSession: \u003csession\u003e\nSecret: \u003csecret\u003e\n```\n\nIf the client framework prevents setting custom HTTP headers during the WebSocket handshake, authorization is performed by sending an `OPEN` message with credentials issued by the [AuthServer](https://github.com/apostoldevel/module-AuthServer). Either an access token (`token`) or a session secret (`secret`) may be used.\n\nAfter successful authorization, `CALL` messages can be sent. The API endpoint is specified in the `Action` field (`a`) and the JSON request body in the `Payload` field (`p`).\n\nAttempting to send a `CALL` before authorization results in a `CALLERROR` response.\n\n**Example — session code not found or session closed:**\n\n```json\n{\"t\":4,\"u\":\"\u003cuuid\u003e\",\"c\":400,\"m\":\"Session code not found.\"}\n```\n\n### Authorization via secret key\n\nRequest:\n\n```json\n{\"t\":0,\"u\":\"\u003cuuid\u003e\",\"p\":{\"secret\": \"MWCJ14k/RJyiHskQB8DoVbliiwDeNGKsgsAMugp3OZt+M0Zj44hDykwRuFoWEwuG\"}}\n```\n\nSuccess response:\n\n```json\n{\"t\":3,\"u\":\"\u003cuuid\u003e\",\"p\":{\"authorized\": true, \"code\": \"amAJmzkxvDE+ad7KwkRtZU1qkUod+3XuycBbxRqHOOjBdeOkkR+lSExI4L8LAcb+\", \"message\": \"Success.\"}}\n```\n\nWhere `code` is a new [authorization code](https://github.com/apostoldevel/module-AuthServer) for obtaining an access token (not to be confused with the session secret).\n\nError response:\n\n```json\n{\"t\":4,\"u\":\"\u003cuuid\u003e\",\"c\":401,\"m\":\"Sign out. Session secret failed verification.\"}\n```\n\n**Note:** If incorrect authorization credentials are supplied, the session is closed but the WebSocket connection remains open.\n\n### Authorization via access token\n\nRequest:\n\n```json\n{\"t\":0,\"u\":\"\u003cuuid\u003e\",\"p\":{\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiIDogImFjY291bnRzLnBsdWdtZS5ydSIsICJhdWQiIDogInNlcnZpY2UtcGx1Z21lLnJ1IiwgInN1YiIgOiAiYzgzYjJmODUzMjFmOTUzNDE3MDc2MjQ1NDZjYTZhYzRmYTZkMTExNSIsICJpYXQiIDogMTYwNjIxMDcwNiwgImV4cCIgOiAxNjA2MjE0MzA2fQ.ZI82FKXAgA1CZm3gx9XCpgpq_WyZJvwqYI4nOdccVts\"}}\n```\n\n**Note:** Access tokens have a limited lifetime.\n\nSuccess response:\n\n```json\n{\"t\":3,\"u\":\"\u003cuuid\u003e\",\"p\":{\"authorized\": true, \"message\": \"Success.\"}}\n```\n\nError response:\n\n```json\n{\"t\":4,\"u\":\"\u003cuuid\u003e\",\"c\":403,\"m\":\"Verification failed: Token expired.\"}\n```\n\nPushing Data to Clients\n-\n\nArbitrary data can be pushed to a connected WebSocket client via a REST API call:\n\n```\nPOST /ws/\u003ccode\u003e[/\u003cidentity\u003e]\n\n\u003canydata\u003e\n```\n\nWhere:\n- `\u003ccode\u003e` — **Required.** Session code of the target WebSocket connection.\n- `\u003cidentity\u003e` — **Optional.** Connection identity within the session (if applicable).\n- `\u003canydata\u003e` — **Optional.** Any data in any format.\n\nThe data is delivered to the client as a `CALL` message with `Action` set to `/ws` and `Payload` containing the body of the REST request.\n\n**Example request:**\n\n```http\nPOST /ws/8c98085f34c83a0eea5f40791218fbf80f1858d3 HTTP/1.1\nHost: localhost:8080\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.[...].9GI82ffkIhbUeWR8if3a8q78nfXAL4AFOMp3kWDTHOA\nContent-Type: application/json\n\n{\"anydata\":null}\n```\n\nSuccess response:\n\n```json\n{\"sent\": true, \"status\": \"Success\"}\n```\n\nError response:\n\n```json\n{\"sent\": false, \"status\": \"Session not found\"}\n```\n\nEvent Subscription\n-\n\nTo receive server-initiated data without polling, a client subscribes to events from a **publisher**.\n\nTo subscribe, choose a publisher and configure a listener (filter and parameters).\n\nPublishers\n-\n\n## Notifications (`notify`)\n\nThe `notify` publisher delivers system events that are raised whenever a user interacts with an object in the system.\n\n### Filter\n\n```json\n{\n  \"entities\": [\"\u003ccode\u003e\", ...],\n  \"classes\":  [\"\u003ccode\u003e\", ...],\n  \"actions\":  [\"\u003ccode\u003e\", ...],\n  \"methods\":  [\"\u003ccode\u003e\", ...],\n  \"objects\":  [\u003cid\u003e, ...]\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`entities` | JSON array of strings | **Optional.** Entity codes.\n`classes` | JSON array of strings | **Optional.** Class codes.\n`actions` | JSON array of strings | **Optional.** Action codes.\n`methods` | JSON array of strings | **Optional.** Method codes.\n`objects` | JSON array of integers | **Optional.** Object IDs.\n\n**Important:** Fields are combined with AND logic; multiple values within a field use OR logic. Fields with no values specified are ignored.\n\n### Parameters\n\n```json\n{\n  \"type\": \"notify | object | mixed | hook\",\n  \"hook\": { ... }\n}\n```\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`type` | STRING | `notify`, `object`, `mixed`, `hook` | **Optional.** Response type.\n`hook` | JSON | Hook object | **Required** when `type` is `hook`.\n\n- `notify` — deliver the raw notification.\n- `object` — deliver the object data as returned by a `/get` request.\n- `mixed` — deliver both the notification and the object data.\n- `hook` — deliver the result of the API request defined in `hook`.\n\n### Hook\n\nA hook defines an API request to execute each time the subscription condition is met.\n\n```json\n{\n  \"method\": \"POST | GET\",\n  \"path\":   \"\u003capi-path\u003e\",\n  \"payload\": { ... }\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`method` | STRING | **Optional.** HTTP method (`POST` or `GET`).\n`path` | STRING | **Required.** REST API path.\n`payload` | JSON | **Optional.** Request payload. Depends on the endpoint.\n\n## Notices (`notice`)\n\nThe `notice` publisher delivers system notices.\n\n### Filter\n\n```json\n{\n  \"categories\": [\"\u003ccode\u003e\", ...]\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`categories` | JSON array of strings | **Optional.** Category codes.\n\n### Parameters\n\n```json\n{\n  \"type\": \"notify\"\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`type` | STRING | **Optional.** Response type. Currently `notify`.\n\n## Messages (`message`)\n\nThe `message` publisher delivers inbound and outbound messages.\n\n### Filter\n\n```json\n{\n  \"classes\":   [\"inbox\", \"outbox\"],\n  \"types\":     [\"\u003ccode\u003e\", ...],\n  \"agents\":    [\"\u003ccode\u003e\", ...],\n  \"codes\":     [\"\u003ccode\u003e\", ...],\n  \"profiles\":  [\"\u003cvalue\u003e\", ...],\n  \"addresses\": [\"\u003cvalue\u003e\", ...],\n  \"subjects\":  [\"\u003cvalue\u003e\", ...]\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`classes` | JSON array | **Optional.** Message direction: `inbox` or `outbox`.\n`types` | JSON array of strings | **Optional.** Agent type codes.\n`agents` | JSON array of strings | **Optional.** Agent codes.\n`codes` | JSON array of strings | **Optional.** Message codes.\n`profiles` | JSON array | **Optional.** Settings profile or sender address.\n`addresses` | JSON array | **Optional.** Recipient address (for API requests — the REST route).\n`subjects` | JSON array | **Optional.** Message subject.\n\n### Parameters\n\n```json\n{\n  \"type\": \"notify\"\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`type` | STRING | **Optional.** Response type. Currently `notify`.\n\n## Event Log (`log`)\n\nThe `log` publisher delivers event log entries.\n\n### Filter\n\n```json\n{\n  \"types\":      [\"M\", \"W\", \"E\", \"D\"],\n  \"codes\":      [\u003cinteger\u003e, ...],\n  \"categories\": [\"\u003ccode\u003e\", ...]\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`types` | JSON array of strings | **Optional.** Log level: `M` (Message), `W` (Warning), `E` (Error), `D` (Debug).\n`codes` | JSON array of integers | **Optional.** Numeric log codes.\n`categories` | JSON array of strings | **Optional.** Category codes.\n\n### Parameters\n\n```json\n{\n  \"type\": \"notify\"\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`type` | STRING | **Optional.** Response type. Currently `notify`.\n\n## Geolocation (`geo`)\n\nThe `geo` publisher delivers incoming geolocation data.\n\n### Filter\n\n```json\n{\n  \"codes\":   [\"\u003ccode\u003e\", ...],\n  \"objects\": [\u003cid\u003e, ...]\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`codes` | JSON array of strings | **Optional.** Coordinate group codes (locations). Defaults to `default`.\n`objects` | JSON array of integers | **Optional.** Object IDs.\n\n### Parameters\n\n```json\n{\n  \"type\": \"notify\"\n}\n```\n\nField | Type | Description\n----- | ---- | -----------\n`type` | STRING | **Optional.** Response type. Currently `notify`.\n\nObserver API\n-\n\n## Subscribe\n\n```\nPOST /api/v1/observer/subscribe\n```\n\nSubscribe to a publisher's events.\n\n**Request fields:**\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`publisher` | STRING | `notify`, `notice`, `message`, `log`, `geo` | **Required.** Publisher code.\n`filter` | JSON | | **Optional.** Event filter.\n`params` | JSON | | **Optional.** Listener parameters.\n\n**Examples:**\n\nSubscribe to all events from the `notify` publisher:\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/observer/subscribe\",\"p\":{\"publisher\":\"notify\"}}\n```\n\nSubscribe with a filter (classes: `client`, `device`) and response type `object`:\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/observer/subscribe\",\"p\":{\"publisher\":\"notify\",\"filter\":{\"classes\":[\"client\",\"device\"]},\"params\":{\"type\":\"object\"}}}\n```\n\nSubscribe to all incoming messages:\n\n```json\n{\"t\":2,\"u\":\"observer\",\"a\":\"/observer/subscribe\",\"p\":{\"publisher\":\"notify\",\"filter\":{\"entities\":[\"message\"],\"classes\":[\"inbox\"],\"actions\":[\"create\"]},\"params\":{\"type\":\"object\"}}}\n```\n\nCatch new client creation and receive the result as a client list:\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/observer/subscribe\",\"p\":{\"publisher\":\"notify\",\"filter\":{\"classes\":[\"client\"],\"actions\":[\"create\"]},\"params\":{\"type\":\"hook\",\"hook\":{\"path\":\"/api/v1/client/list\",\"payload\":{}}}}}\n```\n\n## Unsubscribe\n\n```\nPOST /api/v1/observer/unsubscribe\n```\n\nUnsubscribe from a publisher's events.\n\n**Request fields:**\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`publisher` | STRING | `notify`, `notice`, `message`, `log`, `geo` | **Required.** Publisher code.\n\n**Example:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/observer/unsubscribe\",\"p\":{\"publisher\":\"notify\"}}\n```\n\nPublisher API\n-\n\n## Get publisher data\n\n```\nPOST /api/v1/observer/publisher\n```\n\n**Request fields:**\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`code` | STRING | `notify`, `notice`, `message`, `log`, `geo` | **Required.** Publisher code.\n`fields` | JSON array | | **Optional.** Array of field names to return. If omitted, all fields are returned.\n\n## Get publisher by code\n\n```\nPOST /api/v1/observer/publisher/get\n```\n\n**Request fields:**\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`code` | STRING | `notify`, `notice`, `message`, `log`, `geo` | **Required.** Publisher code.\n`fields` | JSON array | | **Optional.** Array of field names to return. If omitted, all fields are returned.\n\n## Count publishers\n\n```\nPOST /api/v1/observer/publisher/count\n```\n\n**Request fields:** [Common list query parameters](https://github.com/apostoldevel/db-platform#common-list-query-parameters)\n\n## List publishers\n\n```\nPOST /api/v1/observer/publisher/list\n```\n\n**Request fields:** [Common list query parameters](https://github.com/apostoldevel/db-platform#common-list-query-parameters)\n\nListener API\n-\n\n## Get listener data\n\n```\nPOST /api/v1/observer/listener\n```\n\n**Request fields:**\n\nField | Type | Values | Description\n----- | ---- | ------ | -----------\n`publisher` | STRING | `notify`, `notice`, `message`, `log`, `geo` | **Required.** Publisher code.\n`session` | STRING | | **Optional.** Session code.\n`fields` | JSON array | | **Optional.** Array of field names to return. If omitted, all fields are returned.\n\n## Set listener\n\n```\nPOST /api/v1/observer/listener/set\n```\n\n**Request fields:**\n\nField | Type | Description\n----- | ---- | -----------\n`publisher` | STRING | **Required.** Publisher identifier.\n`session` | STRING | **Optional.** Session code.\n`filter` | JSON | **Optional.** Event filter.\n`params` | JSON | **Optional.** Listener parameters.\n\n## Get listener by publisher\n\n```\nPOST /api/v1/observer/listener/get\n```\n\n**Request fields:**\n\nField | Type | Description\n----- | ---- | -----------\n`publisher` | STRING | **Required.** Publisher code.\n`session` | STRING | **Optional.** Session code.\n`fields` | JSON array | **Optional.** Array of field names to return. If omitted, all fields are returned.\n\n## Count listeners\n\n```\nPOST /api/v1/observer/listener/count\n```\n\n**Request fields:** [Common list query parameters](https://github.com/apostoldevel/db-platform#common-list-query-parameters)\n\n## List listeners\n\n```\nPOST /api/v1/observer/listener/list\n```\n\n**Request fields:** [Common list query parameters](https://github.com/apostoldevel/db-platform#common-list-query-parameters)\n\nExamples\n-\n\n**Who am I:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/whoami\"}\n```\n\n**Query entities:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/entity\",\"p\":{\"fields\":[\"id\",\"code\",\"name\"]}}\n```\n\n**Query classes:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/class\",\"p\":{\"fields\":[\"id\",\"entity\",\"entitycode\",\"entityname\",\"code\",\"label\"]}}\n```\n\n**Query actions:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/action\",\"p\":{\"fields\":[\"id\",\"code\",\"name\"]}}\n```\n\n**Query methods:**\n\n```json\n{\"t\":2,\"u\":\"\u003cuuid\u003e\",\"a\":\"/method\",\"p\":{\"fields\":[\"id\",\"class\",\"classcode\",\"classlabel\",\"action\",\"actioncode\",\"actionname\",\"code\",\"label\"]}}\n```\n\nConfiguration\n-\n\n```json\n{\n  \"modules\": {\n    \"WebSocketAPI\": {\n      \"enabled\": true\n    }\n  }\n}\n```\n\nInstallation\n-\n\nFollow the build and installation instructions for [Apostol (C++20)](https://github.com/apostoldevel/libapostol#build-and-installation).\n\n[^crm]: **Apostol CRM** — a template project built on the [A-POST-OL](https://github.com/apostoldevel/libapostol) (C++20) and [PostgreSQL Framework for Backend Development](https://github.com/apostoldevel/db-platform) frameworks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostoldevel%2Fmodule-websocketapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapostoldevel%2Fmodule-websocketapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostoldevel%2Fmodule-websocketapi/lists"}