Der Backup-Server ist eine zweite Adresse, unter der genau dieselbe API läuft. Er ist für den Fall gedacht, dass eine Anfrage an `portal.bulkgate.com` ihr Ziel überhaupt nicht erreicht — der Backup-Host nimmt die Anfrage an und leitet sie über einen anderen Weg weiter.

## Wie der Dienst aufgebaut ist

BulkGate läuft auf mehreren Servern an **drei geografischen Standorten**. Fällt einer davon aus, übernehmen die übrigen den Verkehr automatisch — für Ihre Integration ändert sich nichts und `portal.bulkgate.com` antwortet weiterhin. Diesen Fall müssen Sie auf Ihrer Seite nicht behandeln. Der gesamte Aufbau ist unter [Infrastruktur](https://www.bulkgate.com/de/hilfe-center/allgemeine-informationen/api-infrastruktur/) beschrieben.

Was dies nicht abdeckt, ist **der Weg zu uns**. Ein Ausfall auf der Strecke zwischen Ihrem und unserem Server — bei einem Netzbetreiber, bei einem Konnektivitätsanbieter oder irgendwo dazwischen — liegt außerhalb unserer Kontrolle, und die Anfrage erreicht uns dann gar nicht. Genau dafür ist der Backup-Host da.

Den aktuellen Status des Dienstes finden Sie unter [bulkgate.status.online](https://bulkgate.status.online/en/).

## Adresse

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

Der Host ist ein vollwertiger Ersatz — Pfade, Parameter, Zugangsdaten und Antworten sind identisch mit `portal.bulkgate.com`. Sie tauschen lediglich die Domain aus:

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

Er funktioniert mit demselben Konto, demselben [Token](https://www.bulkgate.com/de/dokumentation/api-verwaltung-und-tokens/api-tokens/) und demselben Guthaben. Es gibt nichts einzurichten und nichts einzuschalten.

> [!CAUTION]
> **Verwenden Sie den Backup-Host nicht als primäre Adresse.** Er kann jederzeit und ohne Vorankündigung wegen Wartungsarbeiten abgeschaltet werden — er soll den Verkehr nur übernehmen, solange der Haupthost nicht erreichbar ist. Lassen Sie `portal.bulkgate.com` in der Reihenfolge an erster Stelle.

## Wann Sie umschalten sollten

> [!IMPORTANT]
> Der Backup-Host löst einen **Verbindungsausfall, keine abgelehnte Anfrage**. Auf eine Anfrage, die die API abgelehnt hat, antwortet er genau gleich.

Schalten Sie um, wenn die Anfrage **keine Antwort erhält**:

| Situation | umschalten? |
|:--------------------------------------------------------------|:-----------|
| Timeout beim Verbindungsaufbau oder beim Lesen                | **Ja**     |
| DNS konnte nicht aufgelöst werden                             | **Ja**     |
| Verbindung abgelehnt, Netzwerk nicht erreichbar               | **Ja**     |
| HTTP 5xx ohne Body                                            | **Ja**     |
| Eine Antwort mit einem [Fehlertyp](https://www.bulkgate.com/de/dokumentation/api-verwaltung-und-tokens/api-fehlertypen/) (4xx) | Nein  |
| `429 Too Many Requests` ([Limits](https://www.bulkgate.com/de/dokumentation/api-verwaltung-und-tokens/limits-fuer-api-anfragen/)) | Nein      |

In den letzten beiden Fällen hat die API geantwortet — die Anfrage ist angekommen und wurde ausgewertet. Eine Wiederholung über den Backup-Host liefert denselben Fehler und verbraucht nur einen weiteren Versuch aus Ihrem Limit.

## Failover in Ihre Integration einbauen

Halten Sie die Adressen in einer geordneten Liste und probieren Sie sie nacheinander aus. Schlägt die Verbindung fehl, gehen Sie zur nächsten über; hat die API geantwortet, geben Sie das Ergebnis unverändert zurück.

```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' => 'Ihre Bestellung 4517 wurde versandt.',
            // Schutz vor doppeltem Versand, wenn beim ersten Versuch ein Timeout auftrat,
            // die Nachricht aber trotzdem verschickt wurde — siehe Worauf Sie achten sollten.
            'duplicates_check' => 'on',
        ], JSON_THROW_ON_ERROR),
    ]);

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

    curl_close($curl);

    // Die Verbindung ist fehlgeschlagen — nächste Adresse versuchen.
    if ($body === false)
    {
        continue;
    }

    // Die API hat geantwortet, ob mit Erfolg oder mit Fehler. Kein weiteres Umschalten.
    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': 'Ihre Bestellung 4517 wurde versandt.',
            'duplicates_check': 'on',
        }, timeout=30)
    except requests.RequestException:
        continue   # die Verbindung ist fehlgeschlagen, nächste Adresse versuchen

    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: 'Ihre Bestellung 4517 wurde versandt.',
        duplicates_check: 'on',
      }),
    });
  } catch {
    continue;   // die Verbindung ist fehlgeschlagen, nächste Adresse versuchen
  }

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

## Worauf Sie achten sollten

> [!WARNING]
> Ein Timeout bedeutet nicht, dass die Nachricht nicht gesendet wurde. Die Anfrage kann angekommen und die Antwort auf dem Rückweg verloren gegangen sein — eine Wiederholung über den Backup-Host würde die Nachricht dann ein zweites Mal senden.

Deshalb sollten Sie bei den **transaktionalen** Endpunkten `duplicates_check` aktiviert senden. Eine Nachricht mit demselben Text an dieselbe Nummer wird innerhalb eines Zeitfensters von **5 Minuten** verworfen, sodass der wiederholte Versuch nichts doppelt versendet.

> [!IMPORTANT]
> Bei **werblichen** Endpunkten schützt `duplicates_check` eine Wiederholung nicht — es entfernt Duplikate nur innerhalb eines einzelnen Versands, nicht über Anfragen hinweg. Eine wiederholte Anfrage ist dafür ein neuer Versand und geht vollständig hinaus. Prüfen Sie bei Massenversand lieber, ob der erste Versuch durchgegangen ist, bevor Sie ihn wiederholen.

Stellen Sie ein sinnvolles Timeout ein. Ohne Timeout wartet der Client auf eine Antwort, die nie kommt, und gelangt gar nicht erst zum Backup-Host.

> [!NOTE]
> **API-Idempotenz** ist in Entwicklung — eine wiederholte Anfrage wird sich kennzeichnen lassen, sodass die API sie erkennt und das Ergebnis der ursprünglichen Anfrage zurückgibt, statt erneut zu senden. Damit entfällt der oben beschriebene Unterschied zwischen transaktionalen und werblichen Endpunkten. Das Vorgehen dokumentieren wir hier, sobald es verfügbar ist.
