Záložný server je druhá adresa, na ktorej beží to isté API. Používa sa, keď sa požiadavka na `portal.bulkgate.com` vôbec nedostane k cieľu — záložný host požiadavku prijme a pošle ju ďalej inou trasou.

## Ako je služba postavená

BulkGate beží na niekoľkých serveroch v **troch geografických lokalitách**. Ak niektorý z nich vypadne, prevádzku automaticky prevezmú zvyšné — z pohľadu integrácie sa nemení nič a `portal.bulkgate.com` odpovedá ďalej. O tento prípad sa starať nemusíte. Celé usporiadanie popisuje [Infraštruktúra](https://www.bulkgate.com/sk/centrum-pomoci/vseobecne-informacie/infrastruktura/).

Čo tým pokryté nie je, je **cesta k nám**. Výpadok na trase medzi vaším serverom a naším — u operátora, poskytovateľa pripojenia alebo kdekoľvek medzi tým — neovplyvníme a požiadavka sa k nám v takom prípade vôbec nedostane. Práve pre taký prípad je tu záložný host.

Aktuálny stav služby nájdete na [bulkgate.status.online](https://bulkgate.status.online/cs/).

## Adresa

```url
https://backup1.bulkgate.com
```

Host je zameniteľný jedna k jednej — cesty, parametre, prihlasovacie údaje aj odpovede sú zhodné s `portal.bulkgate.com`. Stačí teda v adrese vymeniť doménu:

```url
https://portal.bulkgate.com/api/2.0/advanced/transactional
https://backup1.bulkgate.com/api/2.0/advanced/transactional
```

Pracuje sa s rovnakým účtom, rovnakým [tokenom](https://www.bulkgate.com/sk/dokumentacia/api-administracia-a-tokeny/api-tokeny/) aj rovnakým kreditom. Nemusíte nič zakladať ani nikde prepínať.

> [!CAUTION]
> **Nepoužívajte záložný host ako hlavnú adresu.** Kvôli údržbe môže byť kedykoľvek a bez predchádzajúceho upozornenia odstavený — počíta sa s tým, že cez neho ide prevádzka len počas výpadku. `portal.bulkgate.com` musí v poradí zostať prvý.

## Kedy sa naň prepnúť

> [!IMPORTANT]
> Záložný host rieši **výpadok spojenia, nie chybu požiadavky**. Na požiadavku, ktorú API odmietlo, odpovie úplne rovnako.

Prepnite, keď požiadavka **nedostane odpoveď**:

| situácia | prepnúť? |
|:-------------------------------------------------------------|:-----------|
| Timeout spojenia alebo čítania                               | **Áno**    |
| DNS sa nepodarilo preložiť                                   | **Áno**    |
| Spojenie odmietnuté, sieť nedostupná                         | **Áno**    |
| HTTP 5xx bez tela                                            | **Áno**    |
| Odpoveď s [typom chyby](https://www.bulkgate.com/sk/dokumentacia/api-administracia-a-tokeny/typy-chyb-api/) (4xx)      | Nie        |
| `429 Too Many Requests` ([limity](https://www.bulkgate.com/sk/dokumentacia/api-administracia-a-tokeny/limity-api-poziadaviek/)) | Nie     |

Pri posledných dvoch API odpovedalo — požiadavka dorazila a bola vyhodnotená. Zopakovanie na záložnom hoste vráti tú istú chybu a len spotrebuje ďalší pokus z limitu.

## Ako si failover zabudovať do integrácie

Poradie adries si držte v poli a skúšajte ich postupne. Ak zlyhá spojenie, ide sa na ďalšiu; ak API odpovedalo, výsledok sa vráti tak, ako je.

```php
$hosts = ['portal.bulkgate.com', 'backup1.bulkgate.com'];

foreach ($hosts as $host)
{
    $curl = curl_init();

    curl_setopt_array($curl, [
        CURLOPT_URL => "https://$host/api/2.0/advanced/transactional",
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode([
            'application_id' => 451,
            'application_token' => 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj',
            'number' => ['420777777777'],
            'text' => 'Your order 4517 has been shipped.',
            // Poistka proti dvojitému odoslaniu, keď prvý pokus vypršal,
            // ale správa sa aj tak odoslala — pozrite Na čo si dať pozor.
            'duplicates_check' => 'on',
        ], JSON_THROW_ON_ERROR),
    ]);

    $body = curl_exec($curl);
    $error = curl_error($curl);

    curl_close($curl);

    // Spojenie zlyhalo — skúsiť ďalšiu adresu v poradí.
    if ($body === false)
    {
        continue;
    }

    // API odpovedalo, či už úspechom, alebo chybou. Ďalej sa neprepína.
    print_r(json_decode($body, true, flags: JSON_THROW_ON_ERROR));

    break;
}
```

```python
# pip install requests
import requests

hosts = ['portal.bulkgate.com', 'backup1.bulkgate.com']

for host in hosts:
    try:
        response = requests.post(f'https://{host}/api/2.0/advanced/transactional', json={
            'application_id': 451,
            'application_token': 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj',
            'number': ['420777777777'],
            'text': 'Your order 4517 has been shipped.',
            'duplicates_check': 'on',
        }, timeout=30)
    except requests.RequestException:
        continue   # spojenie zlyhalo, skúsiť ďalšiu adresu

    print(response.json())
    break
```

```js
const hosts = ['portal.bulkgate.com', 'backup1.bulkgate.com'];

for (const host of hosts) {
  let response;

  try {
    response = await fetch(`https://${host}/api/2.0/advanced/transactional`, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        application_id: 451,
        application_token: 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj',
        number: ['420777777777'],
        text: 'Your order 4517 has been shipped.',
        duplicates_check: 'on',
      }),
    });
  } catch {
    continue;   // spojenie zlyhalo, skúsiť ďalšiu adresu
  }

  console.log(await response.json());
  break;
}
```

## Na čo si dať pozor

> [!WARNING]
> Timeout neznamená, že sa správa neodoslala. Požiadavka mohla doraziť a odpoveď sa cestou späť stratiť — opakovanie na záložnom hoste by potom správu odoslalo druhýkrát.

Preto pri **transakčných** endpointoch posielajte `duplicates_check` zapnutý. Správa s rovnakým textom na rovnaké číslo sa v okne **5 minút** zahodí, takže opakovaný pokus nič nezdvojí.

> [!IMPORTANT]
> Pri **propagačných** endpointoch `duplicates_check` proti opakovaniu nepomôže — odstraňuje duplicity len v rámci jednej dávky, nie naprieč požiadavkami. Opakovaná požiadavka je preň nová dávka a odíde celá znova. Pri hromadných rozosielkach preto radšej opakujte až po overení, či prvý pokus prešiel.

Nastavte si rozumný timeout. Bez neho klient čaká na odpoveď, ktorá nepríde, a k záložnému hostu sa vôbec nedostane.

> [!NOTE]
> Pripravujeme **idempotenciu API** — opakovanú požiadavku bude možné označiť tak, aby ju API spoznalo a vrátilo výsledok tej pôvodnej namiesto nového odoslania. Tým odpadne rozdiel medzi transakčnými a propagačnými endpointmi popísaný vyššie. Hneď ako bude k dispozícii, doplníme sem postup.
