# Авторизація

## Встановлення WebSocket з'єднання

З'єднання від POS-системи до API Expirenza виконується за допомогою WebSocket.

{% hint style="danger" %}
Під час реалізації WebSocket **необхідно** налаштовувати **повторні спроби з'єднання** з сервером Expirenza **не частіше ніж раз на 15 секунд**.
{% endhint %}

<details>

<summary>Як реалізувати з'єднання правильно на боці інтеграції?</summary>

Так виглядає блок схема того, як сервер Expirenza опитує POS-систему для утримання зʼєднання:

![](/files/EoxaniHfuh78mWz4Rcfe)

1. **Expirenza** посилає **ping** у сокет раз в 15 секунд
2. Очікує наявність **pong** у наступні 1.5 хвилини&#x20;
3. Якщо **pong** не було отримано за 1.5 хвилини - Expirenza розриває з'єднання

POS-системи мають перевіряти (не частіше ніж раз у 15 секунд):

1. Якщо з'єднання немає — намагається під'єднатися,
2. Якщо з'єднання є — перевіряє, коли був останній pong від сервера на ping від інтеграції,
3. Якщо пройшло **більше** ніж 1,5 хвилини — значить, щось не так із з'єднанням, **розриває** його(останній коннект) і намагається під'єднатися ще раз,
4. Якщо з'єднання є і останній ping був **менш** **ніж** 1,5 хвилини тому, значить все добре — інтеграція відправляє pong
5. Якщо після перепідключення сервер одразу дисконнектить - то треба розірвати існуюче зʼєднання, і створити нове

</details>

{% hint style="warning" %}
**Headers**.\
Обов'язкова умова передавати наступні хідери, якщо не передати - авторизація не буде працювати.\
\
`cookie: system={{API}};`\
`Де {{API}} - назва вашої POS системи.`&#x20;

`__`\
`user-agent: Apache-HttpClient/5.2.3 (Java/17.0.7) (Приклад)`\
\&#xNAN;*`Значення для заголовку user-agent  - довільне - як правило - це назва технології що використовується для встановлення http зʼєднання`*
{% endhint %}

Запит на встановлення з'єднання відправляється на адресу з використанням Basic Auth.

Адреса запиту:

```http
wss://api.shaketopay.com.ua/restaurantEntryPoint
```

<details>

<summary>Приклад з'єднання  через websocket</summary>

{% code title="Java" overflow="wrap" lineNumbers="true" %}

```java
import javax.websocket.*;
import javax.websocket.ClientEndpointConfig.Builder;
import javax.websocket.ClientEndpointConfig.Configurator;
import javax.xml.bind.DatatypeConverter;

private final WebsocketEndpoint websocketEndpoint;
private final ClientEndpointConfig clientConfig;
private final URI uri;

    Builder configBuilder = Builder.create();
    String authHeaderValue = "Basic " + DatatypeConverter.printBase64Binary((user + ":" + password).getBytes());
    configBuilder.configurator(new Configurator() {
        @Override
        public void beforeRequest(Map<String, List<String>> headers) {
            headers.put("Authorization", Arrays.asList(authHeaderValue));
        }
    });
    clientConfig = configBuilder.build();
    this.uri = new URI(uri);
    this.websocketEndpoint = new WebsocketEndpoint(messageHandler, new        EventListenerI() {
        @Override
        public void notify(Object o) {
            connected = false;
        }
    });
)

void connect() throws IOException {
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    container.connectToServer(websocketEndpoint, clientConfig, uri);
}

void sendMessage(String message) throws IOException {
    websocketEndpoint.session.getBasicRemote().sendText(message);
}
...
```

{% endcode %}

</details>

***

## Валідація запиту

На стороні Expirenza буде проведена перевірка справжності запиту після надсилання даних від ресторану.&#x20;

Для проходження перевірки на стороні ПЗ ресторану в заголовках кожного запиту повинні міститися параметри `signature`та `restoId`.

{% tabs %}
{% tab title="signature" %}

1. Тіло запиту необхідно підписати алгоритмом HmacSHA256.
2. Результат роботи алгоритму помістити у значення параметра.
   {% endtab %}

{% tab title="restoId" %}
Передати у параметр RESTO\_ID з файлу налаштувань [properties.txt](/api/integration/prepare.md)
{% endtab %}

{% tab title="header user-agent" %}
`user-agent: Apache-HttpClient/5.2.3 (Java/17.0.7) (Приклад)`\
\&#xNAN;*`Значення для заголовку user-agent  - довільне - як правило - це назва технології що використовується для встановлення http зʼєднання`*
{% endtab %}
{% endtabs %}

<details>

<summary>Приклад генерації підпису та додавання її в заголовок signature</summary>

{% code title="JAVA" %}

```java
String signValue = makeSignature(dataBytes);

ResponseEntity<String> bodyEntity = webClient.post()
.uri(urlPart).body(BodyInserters.fromValue(dataBytes))
.header("signature", signValue).retrieve()
.toEntity(String.class).block();

private String makeSignature(byte[] bytes) throws InvalidKeyException, NoSuchAlgorithmException {
    Mac hasher = Mac.getInstance("HmacSHA256");
    hasher.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"));
    byte[] hash = hasher.doFinal(bytes);
    return DatatypeConverter.printBase64Binary(hash);
}
```

{% endcode %}

Де secretKey - це SECRET\_KEY з файлу properties.txt

</details>

{% hint style="info" %}
Приклад підключення за допомогою [Postman](/api/postman.md).
{% endhint %}

***


---

# 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://docs.expirenza.com/api/auth.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.
