# SignalR

## System-defined events

Portos API triggers following system-defined events, which can be handled in client applications:

| Event             | Event name                 | Description                                                    |
| ----------------- | -------------------------- | -------------------------------------------------------------- |
| Resource changed  | `portos.resources.changed` | Raised when resource is changed (created, updated or deleted). |
| License activated | `portos.licence.activated` | Raised when Portos license is activated.                       |

## Receiving Events from Portos API

To receive events from the Portos API, the client application must follow these steps:

1. [Configure authentication](#client-authentication) when communicating with SignalR server.
2. [Register an event Handler](#register-event-handler): specify the client application method to invoke when a notification is sent from the Portos API.
3. [Start the connection](#start-the-connection) to SignalR server.
4. [Subscribe to Events](#subscribe-to-events) using the `Subscribe` method, so the Portos API will deliver notifications to the client application.

{% hint style="info" %}
The code examples below uses JavaScript and [Microsoft's SignalR library](https://learn.microsoft.com/en-us/aspnet/core/signalr/javascript-client). You can install it using npm:

<pre class="language-sh"><code class="lang-sh"><strong>npm install @microsoft/signalr
</strong></code></pre>

{% endhint %}

## Client authentication

When communicating with SignalR server, client application must be authenticated, as described in [Authentication](/authentication/authentication-schemes.md) section. Obtained accces token must be used when communication with notification server.

```javascript
const token = "YOUR_BEARER_TOKEN"; // Replace with your actual token
const serverAddress = "SERVER_ADDRESS"; // Replace with your actual server addess, e.g. http://localhost:3000

const connection = new signalR.HubConnectionBuilder()
    .withUrl(serverAddress + "/signalr/v1/mainHub", {
        accessTokenFactory: () => token
    })
    .build();
```

## Register Event Handler

Use the `connection.on` method to subscribe to the notification events. When a notification is received, the callback function will be executed, and you can handle the notification (e.g., update the UI).

```javascript
connection.on("OnEvent", function (message) {
    // Handle the notification (e.g., update UI)
    if (message.e == "portos.resources.changed") {
        // Resource has been changed
    } else if (message.e == "portos.licence.activated") {
        // Product license has been activated
        const newLicense = message.p;
    }
});
```

The incoming notification is represented by `Notification` class, described below.

#### Notification

| Property name | Type                                                                         | Description                                                                                           |
| ------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `e`           | `string`                                                                     | Event name, as listed in [System-defined events](#system-defined-events).                             |
| `s`           | [`NotificationSender`](#notificationsender)                                  | Information about sender, who sends the message (usually, the server/API).                            |
| `r`           | `string?`                                                                    | Optional notification reference identifier.                                                           |
| `ca`          | `DateTime`                                                                   | "Created At" ISO8601-formatted string representing date and time of notification creation.            |
| `ea`          | `DateTime?`                                                                  | "Expires At" Optional ISO8601-formatted string representing date and time of notification expiration. |
| `p`           | [`License`](/data-models.md#license) `\| ResourceChangedNotificationPayload` | The notification payload. Based on event, payload may vary.                                           |

#### NotificationSender

| Property name | Type                                                                | Description                                                             |
| ------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `c`           | `string`                                                            | Connection identifier.                                                  |
| `u`           | [`NotificationSenderUserIdentity`](#notificationsenderuseridentity) | Information about sender, who performs action resulting in given event. |

#### NotificationSenderUserIdentity

| Property name | Type      | Description                                                                                                          |
| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------- |
| `u`           | `string`  | Unique user name or "System" for system events.                                                                      |
| `d`           | `string`  | Name of device, on which user operates on. Or "System" for system events.                                            |
| `f`           | `string?` | <p>Feature name.<br>Specified if source of event is not user, but system module (feature), a.k.a "virtual user".</p> |

#### ResourceChangedNotificationPayload

| Property name | Type                            | Description                                                                                 |
| ------------- | ------------------------------- | ------------------------------------------------------------------------------------------- |
| `u`           | [`UserIdentity`](#useridentity) |                                                                                             |
| `n`           | `string`                        | One of system-defined [resource names](/resource-names.md).                                 |
| `a`           | `number`                        | <p>Numeric identifier for resource action.<br>1 = Created<br>2 = Updated<br>3 = Deleted</p> |
| `i`           | [`ResourceInfo`](#resourceinfo) | Information about changed resource.                                                         |
| `r`           | `object[]`                      | Collection of affected resources.                                                           |

#### UserIdentity

<table><thead><tr><th width="231.99999999999997">Property name</th><th width="146">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>u</code></td><td><code>string</code></td><td>Unique user identifier.</td></tr><tr><td><code>d</code></td><td><code>string</code></td><td>User display name.</td></tr><tr><td><code>f</code></td><td><code>string?</code></td><td>Name of "feature" (has value only for virtual users).</td></tr></tbody></table>

#### ResourceInfo

<table><thead><tr><th width="231.99999999999997">Property name</th><th width="146">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>i</code></td><td><code>string</code></td><td>Unique resource identifier (e.g. database ID).</td></tr><tr><td><code>n</code></td><td><code>string</code></td><td><a href="/pages/KdiORu1MevfSZngGOg44">Resource name</a>.</td></tr><tr><td><code>v</code></td><td><code>number?</code></td><td>Version of resource.</td></tr></tbody></table>

Example payload for resource changed notification:

```json
{
  "e": "portos.resources.changed", // event name
  "s": { // sender who sends the notification
    "c": "connection-identifier",
    "u": {
      "u": "SYSTEM", // unique user name
      "d": "SYSTEM", // device name
      "f": null // feature name
    }    
  },
  "r": null, // reference ID
  "ca": "2024-07-01T12:51:52.558Z", // created at
  "ea": null, // expires at
  "p": { // notification payload
    "u": { // user who performed action resulting in resource change
      "u": "999", // unique user name
      "d": "BackOffice", // device name
      "f": null // feature name
    },
    "n": "tickets", // resource name
    "a": 1, // action (1 = created, 2 = updated, 3 = deleted)
    "i": { // resource info
      "i": "573f4511088c772684a738f8", // resource ID
      "n": "tickets", // resource name
      "v": 7 // resource version
    },
    "r": [
      { ... }  // the ticket object
    ]
  }
}
```

## Start the connection

To start the connection, await the result of the `start` method call.

```javascript
// Start the connection
await connection.start();
```

## Subscribe to Events

To subscribe to Portos events, a client application must send a "Subscribe" message containing a payload with the subscription details. In the payload, the client application specifies which [system-defined events](#system-defined-events) to subscribe to.

### Subscribe to Resource Changed Event

To subscribe to resource change events, your client application must set `portos.resources.changed` in the payload property's `e` (event name). Optionally, you can also specify a collection of resources. Please refer to the table below:

| Property name | Type                                                              | Description                                                                                                            |
| ------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `e`           | `string`                                                          | The event name. Set to `portos.resources.changed`                                                                      |
| `r`           | [`SubscriptionRequestResource`](#subscriptionrequestresource)`[]` | Optional collection of resources that is client application subscribing to. Leave empty to subscribe to all resources. |

#### SubscriptionRequestResource

| Property name | Type       | Description                                                                                                                                                                                                                 |
| ------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `n`           | `string`   | One of system-defined [resource names](/resource-names.md).                                                                                                                                                                 |
| `a`           | `string[]` | <p>Optional collection of actions that is client application subscribing to. Leave empty to subscribe to all actions. Allowed values:<br><br>- <code>created</code><br>- <code>updated</code><br>- <code>deleted</code></p> |

Example:

<pre class="language-javascript"><code class="lang-javascript">// Prepare the subscription payload
const subscriptionPayload = {
<strong>    e: "portos.resources.changed", // event name
</strong>    r: [ // optional collection of resources
        {
            n: "devices", // resource name
            a: [ // optional collection of actions
                "created",
                "updated",
                "deleted"
            ]
        }
    ]
};

// Send the 'Subscribe' message with the payload
await connection.invoke("Subscribe", subscriptionPayload);
</code></pre>

### Subscribe to License activated event

To subscribe to license activated event, your client application must set `portos.licence.activated` in the payload property  `e` (event name).&#x20;

Example:

```javascript
// Prepare the subscription payload
const subscriptionPayload = {
    e: "portos.licence.activated" // event name
};

// Send the 'Subscribe' message with the payload
await connection.invoke("Subscribe", subscriptionPayload);
```

## Unsubscribe from Events

To unsubscribe, invoke the `Unsubscribe` method with the same parameters used for event subscription.

```javascript
// Prepare the same payload as for subscription
const payload = {
    e: "portos.licence.activated" // event name
};

// Send the 'Unsubscribe' message with the payload
await connection.invoke("Unsubscribe", payload);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.portos.sk/notifications/signalr.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
