# Externes API

Externe Systeme mit GATEWatch verbinden: Zugang, Metadaten, Listen- und Einzelabruf, Gästeimport, Beispiele und Fehlerbehandlung für metadata, pull, fetch und push.

# Übersicht

## Worum es geht

Über die externe API verbinden Sie ein anderes System mit einer GATEWatch-Veranstaltung. Sie können verfügbare Eingabefelder ermitteln, Gästedaten auslesen sowie Gäste anlegen und aktualisieren. Diese Anleitung richtet sich an die technische Betreuung der Anbindung.

## Grundlage: Swagger-Beschreibung

Diese Anleitung erläutert die veröffentlichte [Swagger-Dokumentation „External API for GATEWatch“, Version 1.0.0](https://gwatch.events/ext-api). Die zugrunde liegende [OpenAPI-Beschreibung](https://gwatch.events/openapi.json) enthält Endpunkte, Parameter, Antwortmodelle und Beispiele. Die folgenden Seiten ergänzen diese technische Referenz um den praktischen Ablauf und Fehlerbehandlung.

## Die vier Endpunkte

Die Basisadresse für die hier gezeigten Aufrufe lautet `https://gwatch.events/ext-api`.

<table id="bkmrk-methode-endpunkt-auf"><thead><tr><th>Methode</th><th>Endpunkt</th><th>Aufgabe</th><th>Anleitung</th></tr></thead><tbody><tr><td>`GET`</td><td>`/metadata`</td><td>Importierbare Felder, Sprachen und freigegebene Gates ermitteln.</td><td>[Metadaten](https://doc.gwatch.events/books/externes-api/page/abruf-der-metadaten-metadata)</td></tr><tr><td>`GET`</td><td>`/pull`</td><td>Gästeliste in Seiten abrufen; optional nach Änderungen filtern.</td><td>[Listenabruf](https://doc.gwatch.events/books/externes-api/page/abruf-von-gast-daten-als-liste-pull)</td></tr><tr><td>`GET`</td><td>`/fetch`</td><td>Einen Gast über seinen Ticketcode abrufen.</td><td>[Einzelabruf](https://doc.gwatch.events/books/externes-api/page/abruf-von-daten-eines-einzelnen-gastes-fetch)</td></tr><tr><td>`POST`</td><td>`/push`</td><td>Gäste anlegen oder anhand ihres Ticketcodes aktualisieren.</td><td>[Gäste schreiben](https://doc.gwatch.events/books/externes-api/page/hinzufugen-und-aktualisieren-von-gast-daten-push)</td></tr></tbody></table>

Die GET-Aufrufe verwenden URL-Parameter und benötigen keinen JSON-Body. Bei `push` senden Sie den Body als JSON mit `Content-Type: application/json`. Antworten sind grundsätzlich JSON; insbesondere HTTP 401 kann jedoch einen leeren Body haben. Werten Sie deshalb zuerst den HTTP-Status aus.

## Voraussetzungen und Zugang

Fordern Sie beim zuständigen Teilnehmermanagement folgende Angaben an:

- Den **API-Hauptschlüssel** für die richtige, nicht archivierte Veranstaltung.
- Für `pull` und `fetch` eine aktive **Datenansicht (Flavor)** des passenden Typs und deren Schlüssel.
- Für `push` den zusätzlichen **Import-Schlüssel**, den Swagger als erforderlich ausweist.
- Die Freigabe der ausgehenden IP-Adresse Ihres Servers, falls ein IP-Filter besteht.
- Die vereinbarten Ausgabefelder sowie die für den Import freigegebenen Felder und Gates.

### Header und ihre Bedeutung

<table id="bkmrk-header-verwendung-x-" style="width:100%;"><thead><tr><th style="width:14.6526%;">Header</th><th style="width:85.3276%;">Verwendung</th></tr></thead><tbody><tr><td style="width:14.6526%;">`x-api-key`</td><td style="width:85.3276%;">Bei allen vier Endpunkten erforderlich. Der Schlüssel bestimmt die Veranstaltung; eine zusätzliche Veranstaltungs-ID wird nicht übergeben.</td></tr><tr><td style="width:14.6526%;">`x-api-flavor`</td><td style="width:85.3276%;">Bei `pull` und `fetch`: Schlüssel der jeweiligen Datenansicht. Weglassen funktioniert nur, wenn eine aktive Ansicht mit leerem Schlüssel und passendem Typ eingerichtet ist.</td></tr><tr><td style="width:14.6526%;">`x-api-push`</td><td style="width:85.3276%;">Bei `push`: Laut Swagger erforderlicher Import-Schlüssel (`ApiPushHeader`). Den passenden Wert beim Teilnehmermanagement anfordern.</td></tr><tr><td style="width:14.6526%;">`Accept`</td><td style="width:85.3276%;">Verwenden Sie `application/json`.</td></tr><tr><td style="width:14.6526%;">`Content-Type`</td><td style="width:85.3276%;">Bei `push`: `application/json`.</td></tr></tbody></table>

Ein Flavor für `pull` ist nicht automatisch für `fetch` verwendbar. Die Datenansichten werden getrennt nach Endpunkttyp konfiguriert. `metadata` benötigt keinen Flavor.

Verwenden Sie Schlüssel in den Headern und bewahren Sie sie in der serverseitigen Konfiguration auf. Die Beispiele enthalten nur Platzhalter; sie sind vor einem eigenen Test zu ersetzen.

### IP-Filter

Für die Veranstaltung kann eine Liste erlaubter IP-Adressen hinterlegt sein. Ein eigener, nicht leerer IP-Filter der gewählten Datenansicht **ersetzt** bei `pull` beziehungsweise `fetch` den allgemeinen Filter. Ohne eigenen Filter gilt der allgemeine Filter.

Geprüft wird die vom Portal ermittelte IP-Adresse der Anfrage. Lassen Sie deshalb auch die tatsächliche ausgehende Adresse Ihrer Testumgebung freigeben. Die aktuelle Implementierung vergleicht einzelne Adressen; CIDR-Netze und Wildcards sind keine unterstützte Schreibweise dieser Filter.

## Empfohlener Einstieg

1. Rufen Sie `metadata` ab und kontrollieren Sie den Veranstaltungsnamen.
2. Stimmen Sie die gewünschte Leseansicht mit dem Teilnehmermanagement ab.
3. Prüfen Sie `pull` mit einem kleinen `limit` oder `fetch` mit einem bekannten Test-Ticketcode.
4. Ordnen Sie die Felder Ihres Systems den tatsächlich gelieferten Feldschlüsseln zu.
5. Testen Sie `push` mit abgestimmten Testdaten und kontrollieren Sie jedes Einzelergebnis.

In [Swagger](https://gwatch.events/ext-api) öffnen Sie den gewünschten Endpunkt. Unter **Authorize** hinterlegen Sie die Schlüssel; über **Try it out** geben Sie Parameter beziehungsweise den Request-Body ein und starten mit **Execute** den Aufruf. Die Bereiche **Example Value** und **Schema** zeigen Beispielwerte und die Datenstruktur. **Ein `push`-Aufruf schreibt echte Daten in die über den Hauptschlüssel ausgewählte Veranstaltung.** Verwenden Sie dafür eine vereinbarte Testveranstaltung.

## Schreibfelder und Lesefelder unterscheiden

`metadata.guest` beschreibt die zulässigen **Eingabeschlüssel für `push`**, beispielsweise `GUEST_FIRST_NAME`. **Bei beiden Exportvarianten (`pull` und `fetch`) legt immer die Administration die fachlichen Ausgabefeldnamen und deren Inhalte fest.** Ein Feld kann einen einzelnen Wert oder zusammengesetzte Inhalte enthalten. Beispielsweise kann die Administration ein Feld `Name` definieren, das Vor- und Nachname zusammen ausgibt. Die festen Verwaltungsfelder von `pull` (`id`, `created`, `updated`, `deleted`) werden zusätzlich vom Portal ergänzt.

Kopieren Sie eine Leseantwort daher nicht unverändert in einen Schreibaufruf. Auch Datums-, Listen- und Ja/Nein-Ausgaben sind nicht automatisch geeignete Eingabewerte.

## HTTP-Status im Überblick

<table id="bkmrk-status-bedeutung-200"><thead><tr><th>Status</th><th>Bedeutung</th></tr></thead><tbody><tr><td>`200`</td><td>Erfolgreicher Abruf oder vollständig erfolgreicher `push`.</td></tr><tr><td>`207`</td><td>Bei `push` ist mindestens ein Datensatz fehlgeschlagen; auch alle Datensätze können betroffen sein. `summary` und `results` auswerten.</td></tr><tr><td>`401`</td><td>Zugang abgewiesen: Hauptschlüssel, Archivstatus, Flavor-Typ/Aktivierung, Import-Schlüssel oder IP-Filter prüfen. Der Body kann leer sein.</td></tr><tr><td>`403`</td><td>Bei `fetch`: Ein bestehender Gast erfüllt die Filterbedingungen der Datenansicht nicht.</td></tr><tr><td>`404`</td><td>Bei `fetch`: Kein entsprechender Gast gefunden.</td></tr><tr><td>`422`</td><td>Anfrageparameter beziehungsweise die äußere Struktur des Schreibaufrufs sind ungültig.</td></tr></tbody></table>

Die Antwortstrukturen unterscheiden sich je Endpunkt. Ein Feld `error` ist nicht in jeder Antwort enthalten. Bei unerwarteten Serverfehlern keine automatische Schreibwiederholung ohne Prüfung des bereits gespeicherten Ergebnisses durchführen.

**Weiter:** [Abruf der Metadaten](https://doc.gwatch.events/books/externes-api/page/abruf-der-metadaten-metadata).

# Abruf der Metadaten (metadata)

**Swagger-Referenz:** [Operation und Antwortschema öffnen](https://gwatch.events/ext-api#//get_ext_api_metadata).

## Worum es geht

`metadata` beschreibt die Veranstaltung und die verfügbaren **Eingabefelder für `push`**. Rufen Sie diese Angaben vor der Einrichtung eines Imports ab und prüfen Sie sie erneut, wenn die Veranstaltungskonfiguration geändert wurde.

## Aufruf

```bash
curl --request GET 'https://gwatch.events/ext-api/metadata' \
  --header 'x-api-key: IHR_HAUPTSCHLUESSEL' \
  --header 'Accept: application/json'

```

Benötigt werden der Hauptschlüssel und gegebenenfalls die Freigabe Ihrer IP-Adresse. Ein Flavor- oder Import-Schlüssel ist für diesen Aufruf nicht erforderlich.

## Aufbau der Antwort

Die Antwort enthält direkt die Bereiche `event`, `guest` und `gates`, ohne zusätzliches `error`-Feld.

<table id="bkmrk-bereich-inhalt-event"><thead><tr><th>Bereich</th><th>Inhalt</th></tr></thead><tbody><tr><td>`event`</td><td>Veranstaltungsname, Datum, Standardlänge automatisch erzeugter Ticketcodes und verfügbare Sprachen.</td></tr><tr><td>`guest`</td><td>Array der importierbaren Felder mit `key`, `name`, `type` und gegebenenfalls `restrictions` oder `items`.</td></tr><tr><td>`gates`</td><td>Array der für die API freigegebenen Gates mit `id` und `name`. Es kann leer sein.</td></tr></tbody></table>

Die folgende gültige JSON-Darstellung ist ein **gekürztes Beispiel nach den Swagger-Modellen** mit einer Auswahl von Feldern. Beispielgrenzen sind keine festen Vorgaben für Ihre Veranstaltung:

```json
{
  "event": {
    "name": "IT seminar",
    "date": "2025-05-31",
    "defaultTicketCodeLength": 10,
    "locales": [
      "de",
      "en"
    ]
  },
  "guest": [
    {
      "key": "GUEST_TICKET_CODE",
      "name": "Ticket code",
      "type": "singleLineText",
      "restrictions": {
        "nullable": false,
        "unique": true,
        "min": 6,
        "max": 12
      }
    },
    {
      "key": "GUEST_LOCALE",
      "name": "Locale",
      "type": "list",
      "items": [
        {
          "key": "de",
          "value": "Deutsch"
        },
        {
          "key": "en",
          "value": "English"
        }
      ],
      "restrictions": {
        "nullable": false
      }
    },
    {
      "key": "GUEST_NAME",
      "name": "Name",
      "type": "singleLineText",
      "restrictions": {
        "max": 65535
      }
    }
  ],
  "gates": [
    {
      "id": 6398,
      "name": "Sicherheit von Websites"
    },
    {
      "id": 6399,
      "name": "Anti-Viren Software aktuell"
    }
  ]
}

```

## Feldschlüssel und Einschränkungen

- **`key`** wird beim Schreiben unverändert als JSON-Schlüssel verwendet. Groß-/Kleinschreibung beachten.
- **`name`** ist die lesbare Bezeichnung zur Abstimmung mit dem Teilnehmermanagement.
- **`type`** bestimmt das vorgesehene Eingabeformat.
- **`restrictions`** beschreibt zusätzliche Grenzen, etwa `min`, `max`, `nullable`, `unique`, `maxWidth` oder `maxHeight`.

`nullable: false` bedeutet: Wenn Sie das Feld senden, darf sein Wert nicht `null` sein. Das ist keine generelle Pflicht, das Feld in jedem Datensatz zu senden. Weggelassene Felder werden beim Aktualisieren nicht gezielt überschrieben; bei neuen Gästen greifen die jeweiligen Vorgaben beziehungsweise Standardwerte.

`defaultTicketCodeLength` ist die Standardlänge generierter Codes. Eigene Codes können davon abweichen, müssen aber die Restriktionen von `GUEST_TICKET_CODE` einhalten. Senden Sie Ticketcodes als Zeichenfolge, damit führende Nullen erhalten bleiben.

Zu den Standardfeldern gehören `GUEST_TICKET_CODE`, `GUEST_LOGIN`, `GUEST_PASSWORD`, `GUEST_LOCALE`, `GUEST_ACTIVE`, `GUEST_VALID_FROM` und `GUEST_VALID_TO`. Weitere Gästefelder erscheinen nur bei entsprechender API-Freigabe. Verwenden Sie die tatsächlich gelieferte Feldliste.

## Eingabeformate

<table id="bkmrk-typ-empfohlener-json"><thead><tr><th>Typ</th><th>Empfohlener JSON-Wert</th></tr></thead><tbody><tr><td>`singleLineText`</td><td>Zeichenfolge ohne Zeilenumbruch.</td></tr><tr><td>`multiLineText`</td><td>Zeichenfolge; Zeilenumbrüche in JSON als `\n`.</td></tr><tr><td>`email`</td><td>Formal gültige E-Mail-Adresse.</td></tr><tr><td>`url`</td><td>Vollständige gültige URL.</td></tr><tr><td>`numeric`</td><td>Zahl mit Dezimalpunkt, beispielsweise `12.5`.</td></tr><tr><td>`integer`</td><td>Ganzzahl, beispielsweise `3`.</td></tr><tr><td>`boolean`</td><td>JSON-Werte `true` oder `false`. Verlassen Sie sich nicht auf lokalisierte Zeichenfolgen wie `Ja` oder `Nein`.</td></tr><tr><td>`date`</td><td>Zeichenfolge im Format `YYYY-MM-DD`.</td></tr><tr><td>`dateTime`</td><td>Zeichenfolge im Format `YYYY-MM-DDTHH:MM:SS`. Die verwendete Portal-Zeitzone vor der Anbindung abstimmen.</td></tr><tr><td>`list`</td><td>Einen der unter `items` gelieferten **Schlüssel** verwenden.</td></tr><tr><td>`image`</td><td>Bild als eingebettete Data-URI, beispielsweise mit dem Präfix `data:image/png;base64,` und anschließendem Base64-Bildinhalt.</td></tr></tbody></table>

Bildfelder enthalten Größenangaben in den Restriktionen. Die Bildverarbeitung kann zu große Bilder beim Speichern proportional verkleinern. Eine gewöhnliche externe Bild-URL ist nicht das hier beschriebene Importformat.

## Listen mit mehreren Sprachen

Bei benutzerdefinierten Listen kann ein Eintrag statt `value` eine sprachabhängige Zuordnung `values` enthalten:

```json
{
  "key": "GUEST_FOOD",
  "name": "Food",
  "type": "list",
  "items": [
    {
      "key": "ID_164h656yn",
      "values": {
        "de": "Keine Einschränkungen",
        "en": "No restrictions"
      }
    },
    {
      "key": "ID_6rkyfap8y",
      "values": {
        "de": "Vegetarisch",
        "en": "Veggie"
      }
    },
    {
      "key": "ID_ncg2151l7",
      "values": {
        "de": "Vegan",
        "en": "Vegan"
      }
    }
  ],
  "restrictions": {
    "nullable": true
  }
}

```

Beim Schreiben verwenden Sie hier beispielsweise `"GUEST_FOOD": "ID_6rkyfap8y"` für die vegetarische Auswahl. Die sichtbare Bezeichnung wird nicht als Eingabeschlüssel verwendet. Der Feldname ist beispielhaft und muss in Ihren Metadaten tatsächlich vorkommen.

## Gates verwenden

Gates können Sessions, Veranstaltungstage oder andere Zugangsbereiche darstellen. Nur die unter `gates` aufgeführten IDs sind für die API-Zuweisung freigegeben. Wie Sie eine Gate-Auswahl übermitteln und was beim Weglassen oder Leeren passiert, beschreibt [push](https://doc.gwatch.events/books/externes-api/page/hinzufugen-und-aktualisieren-von-gast-daten-push).

## Typische Probleme

<table id="bkmrk-problem-pr%C3%BCfung-http"><thead><tr><th>Problem</th><th>Prüfung</th></tr></thead><tbody><tr><td>HTTP 401</td><td>Hauptschlüssel, Veranstaltung und allgemeinen IP-Filter prüfen. Archivierte Veranstaltungen sind ausgeschlossen.</td></tr><tr><td>Ein Gästefeld fehlt</td><td>API-Freigabe des Feldes prüfen lassen.</td></tr><tr><td>Ein Gate fehlt</td><td>API-Freigabe des Gates prüfen lassen.</td></tr><tr><td>Ausgabefeld aus `pull` ist hier nicht enthalten</td><td>Lesefelder und Eingabeschlüssel sind getrennte Konfigurationen. Zuordnung vereinbaren.</td></tr></tbody></table>

**Weiter:** [Gästeliste abrufen](https://doc.gwatch.events/books/externes-api/page/abruf-von-gast-daten-als-liste-pull).  
**Zurück:** [Übersicht](https://doc.gwatch.events/books/externes-api/page/ubersicht).

# Abruf von Gast-Daten als Liste (pull)

**Swagger-Referenz:** [Operation und Antwortschema öffnen](https://gwatch.events/ext-api#//get_ext_api_pull).

## Worum es geht

`pull` liefert die für Ihre Datenansicht freigegebenen Gäste in aufeinanderfolgenden Seiten. Über einen Änderungszeitpunkt können Sie den Abruf auf neuere Änderungen eingrenzen.

## Aufruf

```bash
curl --get 'https://gwatch.events/ext-api/pull' \
  --header 'x-api-key: IHR_HAUPTSCHLUESSEL' \
  --header 'x-api-flavor: IHR_PULL_SCHLUESSEL' \
  --header 'Accept: application/json' \
  --data-urlencode 'limit=100' \
  --data-urlencode 'offset=0'

```

Der Flavor muss aktiv und vom Typ **pull** sein. Bei einer vereinbarten Standardansicht mit leerem Schlüssel lassen Sie den Flavor-Header weg. Allgemeine Zugangsvoraussetzungen stehen in der [Übersicht](https://doc.gwatch.events/books/externes-api/page/ubersicht).

## Optionale URL-Parameter

<table id="bkmrk-parameter-bedeutung-"><thead><tr><th>Parameter</th><th>Bedeutung</th></tr></thead><tbody><tr><td>`limit`</td><td>Anzahl pro Seite: Ganzzahl von `1` bis `2500`. Ohne Angabe werden im aktuellen Portal bis zu `2500` Gäste angefordert.</td></tr><tr><td>`offset`</td><td>Anzahl zu überspringender Datensätze, mindestens `0`. Standard: `0`.</td></tr><tr><td>`changesSince`</td><td>Untere Änderungsgrenze: Berücksichtigt werden Datensätze mit einer erfassten Änderung **nach** diesem Zeitpunkt. Ohne Angabe entfällt der Zeitfilter. Format: `YYYY-MM-DDTHH:MM:SS`, beispielsweise `2026-09-18T10:00:00`.</td></tr></tbody></table>

Der Änderungsfilter berücksichtigt Gaständerungen einschließlich Löschung, Teilnahmestatus und Änderungen durch den Gast sowie Änderungen und Löschungen an Gästefeldern. Er ist kein vollständiges Ereignisprotokoll aller abhängigen Daten oder Konfigurationsänderungen.

## Antwort verstehen

Antwortauszug nach dem Swagger-Modell `pullData`, mit `limit=1` und insgesamt zwei verfügbaren Gästen:

```json
{
  "error": false,
  "meta": {
    "changesSince": null,
    "available": 2,
    "limit": 1,
    "offset": 0,
    "nextUrl": "https://gwatch.events/ext-api/pull?limit=1&offset=1"
  },
  "event": {
    "name": "IT summit",
    "ort": "Frankfurt am Main"
  },
  "guests": [
    {
      "First name": "Susi",
      "Surname": "Sorglos",
      "Access": "IT-Security Concepts",
      "Last scan": "20.03.2025 19:57:57",
      "id": 347639,
      "created": "2017-01-07T20:08:30",
      "updated": "2025-03-20T20:13:47",
      "deleted": false
    }
  ]
}

```

<table id="bkmrk-bereich-bedeutung-me"><thead><tr><th>Bereich</th><th>Bedeutung</th></tr></thead><tbody><tr><td>`meta.available`</td><td>Zahl der zur aktuellen Abfrage passenden Gäste vor der Seiteneinteilung.</td></tr><tr><td>`meta.nextUrl`</td><td>URL der nächsten Seite; `null`, wenn keine weitere Seite folgt.</td></tr><tr><td>`event`</td><td>Konfigurierte Veranstaltungsfelder. Ohne konfigurierte Felder kann dieser Bereich als leeres Array `[]` erscheinen.</td></tr><tr><td>`guests`</td><td>Array mit den Datensätzen dieser Seite. Die Reihenfolge richtet sich nach aufsteigender Gast-ID.</td></tr></tbody></table>

**Die Administration legt sämtliche fachlichen Feldnamen und Feldinhalte des Listenexports fest** – sowohl für `event` als auch für die Gäste. Dabei sind auch zusammengesetzte Inhalte möglich, etwa ein Feld `Name` mit Vor- und Nachname. Die Felder `First name`, `Surname`, `Access`, `Last scan`, `name` und `ort` stammen lediglich aus den Swagger-Beispielen und sind keine fest vorgegebenen API-Feldnamen. Zusätzlich erhält jeder Gast vier feste Felder:

- `id`: Datenbank-ID des Gastes.
- `created`: Erstellungszeitpunkt als `YYYY-MM-DDTHH:MM:SS`.
- `updated`: Letzter aus den ausgewerteten Gast- und Gästefeld-Zeitstempeln ermittelter Änderungszeitpunkt.
- `deleted`: JSON-Boolean für den Löschstatus.

Reservieren Sie diese vier Namen in Ihrer Feldvereinbarung. Sie werden vom Portal für die festen Angaben verwendet.

## Alle Seiten abrufen

1. Beginnen Sie mit `offset=0` und einem passenden `limit`, etwa `100`.
2. Verarbeiten Sie die zurückgegebenen Gäste.
3. Rufen Sie `meta.nextUrl` auf, solange der Wert nicht `null` ist. Senden Sie bei jeder Folgeseite dieselben Authentifizierungsheader mit.
4. Prüfen Sie, dass die Folge-URL zum vereinbarten API-Host gehört, bevor Sie Schlüssel mitsenden.

Alternativ erhöhen Sie den Offset selbst um das Limit: `0`, `100`, `200` usw. Behalten Sie den Änderungsfilter während eines Durchlaufs unverändert bei.

## Gelöschte und ausgefilterte Gäste

Auch als gelöscht markierte Gäste können in der Liste enthalten sein. Entscheidend ist `deleted=true`. **Konfigurierte Ausgabefelder sind dabei nicht garantiert leer.** Verwenden Sie den Löschstatus, um Ihre lokale Kopie entsprechend zu behandeln.

Die Bedingungen der Datenansicht filtern die Ergebnismenge zusätzlich. Fällt ein zuvor sichtbarer Gast später aus diesen Bedingungen heraus, ist damit keine eigene Löschmeldung an Ihr System garantiert. Stimmen Sie einen regelmäßigen Bestandsabgleich ab, wenn Ihre Anbindung solche Änderungen erkennen muss.

## Änderungen synchronisieren

- Speichern Sie Gäste anhand ihrer `id`, nicht anhand ihrer Position in der Antwort.
- Setzen Sie den nächsten Synchronisationsstand erst nach erfolgreicher Verarbeitung aller Seiten.
- Arbeiten Sie mit einem zeitlichen Überlappungsbereich und verarbeiten Sie Wiederholungen anhand der ID. So werden Änderungen an der Sekundengrenze nicht allein durch den strikten Zeitvergleich übersehen.
- Offset-Seiten bilden keinen eingefrorenen Datenstand. Gleichzeitige Änderungen an Gästen oder Filtern können die Seiteneinteilung verschieben; ein regelmäßiger vollständiger Abgleich bleibt sinnvoll.

Die API liefert hierfür keinen Snapshot- oder Ereignis-Cursor. Ein lückenloses Änderungsprotokoll lässt sich allein aus `changesSince` nicht ableiten.

## Formate der vereinbarten Ausgabefelder

Die Ausgabe hängt vom verwendeten Feld beziehungsweise Platzhalter ab. Benutzerdefinierte Datumsfelder werden im aktuellen Code als `YYYY-MM-DD` beziehungsweise `YYYY-MM-DDTHH:MM:SS` eingesetzt; andere Platzhalter können anders formatieren. Listen und Ja/Nein-Felder können lesbare Bezeichnungen enthalten.

Eine durchgehend an der Sprache jedes einzelnen Gastes ausgerichtete Ausgabe ist nicht zugesichert. Vereinbaren und testen Sie deshalb die Formate Ihrer Datenansicht ausdrücklich. Für den Rückimport gelten die Eingabeformate aus [metadata](https://doc.gwatch.events/books/externes-api/page/abruf-der-metadaten-metadata).

## Fehler

Ungültige Parameter liefern HTTP 422, beispielsweise bei `limit=0`:

```json
{
  "error": true,
  "message": {"limit": ["The limit must be at least 1."]}
}

```

Der genaue Meldungstext kann sprachabhängig abweichen. HTTP 401 weist auf Zugang, Flavor oder IP-Filter hin. Eine gültige Abfrage ohne Treffer liefert HTTP 200 und `guests: []`.

**Weiter:** [Einzelnen Gast abrufen](https://doc.gwatch.events/books/externes-api/page/abruf-von-daten-eines-einzelnen-gastes-fetch).  
**Zurück:** [Metadaten](https://doc.gwatch.events/books/externes-api/page/abruf-der-metadaten-metadata).

# Abruf von Daten eines einzelnen Gastes (fetch)

**Swagger-Referenz:** [Operation und Antwortschema öffnen](https://gwatch.events/ext-api#//get_ext_api_fetch).

## Worum es geht

Mit `fetch` lesen Sie die vereinbarten Ausgabefelder eines einzelnen Gastes über dessen Ticketcode aus. **Die Administration legt immer die Ausgabefeldnamen und deren Inhalte fest.** Dazu gehören auch zusammengesetzte Feldinhalte, beispielsweise ein Feld `Name`, das Vor- und Nachname zusammen ausgibt. Die Felder und Filter werden in einer eigenen Datenansicht vom Typ **fetch** festgelegt.

## Aufruf

```bash
curl --get 'https://gwatch.events/ext-api/fetch' \
  --header 'x-api-key: IHR_HAUPTSCHLUESSEL' \
  --header 'x-api-flavor: IHR_FETCH_SCHLUESSEL' \
  --header 'Accept: application/json' \
  --data-urlencode 'code=TEST0001'

```

Ersetzen Sie `TEST0001` durch den Ticketcode des gesuchten Gastes. Durch `--data-urlencode` werden auch Sonderzeichen korrekt als URL-Parameter übertragen.

<table id="bkmrk-parameter-vorgabe-co"><thead><tr><th>Parameter</th><th>Vorgabe</th></tr></thead><tbody><tr><td>`code`</td><td>Erforderliche, nicht leere Zeichenfolge mit dem Ticketcode. Keine Datenbank-ID.</td></tr></tbody></table>

Der Hauptschlüssel bestimmt die Veranstaltung. Ein Flavor vom Typ `pull` wird hier nicht akzeptiert. Das Weglassen von `x-api-flavor` setzt eine aktive Standardansicht mit leerem Schlüssel vom Typ `fetch` voraus.

## Erfolgreiche Antwort

Bei HTTP 200 werden die vereinbarten Gastfelder **direkt** zurückgegeben, wie im Swagger-Modell `fetchData`:

```json
{
  "First name": "Susi",
  "Surname": "Sorglos",
  "Access": "IT-Security Concepts"
}

```

Die Namen `First name`, `Surname` und `Access` im Beispiel sind von der Administration gewählte Bezeichnungen; Ihre Variante kann vollständig andere Feldnamen und zusammengesetzte Werte liefern. Verwenden Sie für Ihre Anbindung die mit der Administration abgestimmte Zuordnung.

Es gibt keinen zusätzlichen Bereich `guests`, `event` oder `meta` und kein automatisch ergänztes `error`-Feld. Anders als bei `pull` werden auch `id`, `created`, `updated` und `deleted` nicht automatisch angefügt. Benötigen Sie zusätzliche Angaben, müssen diese mit dem Teilnehmermanagement als Ausgabefelder vereinbart werden.

Ohne konfigurierte Gastfelder kann die erfolgreiche Antwort ein leeres Array `[]` sein.

## Filter und Formate

Die Datenansicht kann den Abruf auf bestimmte Gäste begrenzen, beispielsweise anhand einer Zustimmung oder eines Teilnahmemerkmals. HTTP 403 bedeutet deshalb nicht zwingend eine fehlende Einwilligung, sondern allgemein: Der bestehende Gast erfüllt die konfigurierten Bedingungen nicht.

Wie bei `pull` hängen Werte und Formate von den konfigurierten Feldern und Platzhaltern ab. Eine pauschale Lokalisierung nach der Sprache des jeweiligen Gastes ist nicht zugesichert. Stimmen Sie erwartete Werte insbesondere für Listen, Ja/Nein-Felder und Zeitangaben ab.

`fetch` liefert keinen festen Löschstatus. Ein HTTP-200-Ergebnis allein ist daher kein verlässlicher Nachweis, dass ein Gast nicht gelöscht oder noch teilnahmeberechtigt ist. Für einen Bestandsabgleich verwenden Sie [pull einschließlich `deleted`](https://doc.gwatch.events/books/externes-api/page/abruf-von-gast-daten-als-liste-pull).

## Statusmeldungen

<table id="bkmrk-http-status-bedeutun"><thead><tr><th>HTTP-Status</th><th>Bedeutung und nächster Schritt</th></tr></thead><tbody><tr><td>`200`</td><td>Datensatz wurde entsprechend der Datenansicht geliefert.</td></tr><tr><td>`401`</td><td>Hauptschlüssel, Archivstatus, aktiven Flavor vom Typ `fetch` und IP-Filter prüfen. Der Body kann leer sein.</td></tr><tr><td>`403`</td><td>Gast vorhanden, aber durch die Bedingungen der Datenansicht ausgeschlossen. Filter mit dem Teilnehmermanagement prüfen.</td></tr><tr><td>`404`</td><td>Kein entsprechender Gast gefunden. Veranstaltung und Ticketcode prüfen.</td></tr><tr><td>`422`</td><td>`code` fehlt, ist leer oder kein geeigneter Zeichenfolgenwert.</td></tr></tbody></table>

Für 403 und 404 wird keine fachliche Fehlerbeschreibung mitgeliefert; rechnen Sie mit einem leeren JSON-Ergebnis statt eines `message`-Objekts. Verarbeiten Sie diese Fälle anhand des HTTP-Status.

Beispiel einer Validierungsantwort bei fehlendem `code`:

```json
{
  "error": true,
  "message": {"code": ["The code parameter is missing."]}
}

```

Der konkrete Meldungstext kann sprachabhängig abweichen.

## Funktion prüfen

1. Einen bekannten Ticketcode abrufen und die vereinbarten Felder kontrollieren.
2. Einen nicht vorhandenen Testcode prüfen; erwartet wird HTTP 404.
3. Falls Filter eingerichtet sind, einen abgestimmten Testgast außerhalb dieser Bedingungen prüfen; erwartet wird HTTP 403.
4. Einen Aufruf ohne `code` prüfen; bei gültigem Zugang wird HTTP 422 erwartet.

**Weiter:** [Gäste anlegen und aktualisieren](https://doc.gwatch.events/books/externes-api/page/hinzufugen-und-aktualisieren-von-gast-daten-push).  
**Zurück:** [Gästeliste abrufen](https://doc.gwatch.events/books/externes-api/page/abruf-von-gast-daten-als-liste-pull).

# Hinzufügen und Aktualisieren von Gast-Daten (push)

**Swagger-Referenz:** [Operation und Antwortschema öffnen](https://gwatch.events/ext-api#//post_ext_api_push).

## Worum es geht

Mit `push` übertragen Sie bis zu **100 Gast-Datensätze pro Anfrage**. Das Portal legt neue Gäste an oder aktualisiert bestehende Gäste anhand von `GUEST_TICKET_CODE`.

**Dieser Aufruf verändert Daten.** Prüfen Sie Hauptschlüssel und Veranstaltungsnamen zunächst über `metadata` und beginnen Sie mit abgestimmten Testdaten.

## Aufruf und Header

Speichern Sie den JSON-Body in einer lokalen Datei `push.json`. Senden Sie ihn beispielsweise so:

```bash
curl --request POST 'https://gwatch.events/ext-api/push' \
  --header 'x-api-key: IHR_HAUPTSCHLUESSEL' \
  --header 'x-api-push: IHR_IMPORTSCHLUESSEL' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data-binary '@push.json'

```

Swagger weist für `push` sowohl `x-api-key` als auch `x-api-push` als erforderlich aus. Fordern Sie beide Schlüssel für die Anbindung an. Ein Flavor-Schlüssel wird bei `push` nicht verwendet.

Für Imports muss die Administration einen Import-Schlüssel für die Veranstaltung vergeben. Übertragen Sie diesen im Header `x-api-push`. Ohne eingerichteten Import-Schlüssel sowie bei fehlendem, leerem oder falschem Schlüssel wird der Import mit HTTP `401` abgewiesen.

## Aufbau der Anfrage

<table id="bkmrk-feld-vorgabe-meta.fa" style="width:100%;"><thead><tr><th style="width:18.711%;">Feld</th><th style="width:81.2691%;">Vorgabe</th></tr></thead><tbody><tr><td style="width:18.711%;">`meta.failIfExists`</td><td style="width:81.2691%;">Erforderlicher Boolean: `true` weist vorhandene Ticketcodes ab; `false` erlaubt Aktualisierungen.</td></tr><tr><td style="width:18.711%;">`meta.insertAs`</td><td style="width:81.2691%;">Erforderliche Ganzzahl: `1` für bereits bestätigte neue Gäste, `2` für neue Gäste mit ausstehender Bestätigung. Wird nur bei Neuanlage berücksichtigt.</td></tr><tr><td style="width:18.711%;">`guests`</td><td style="width:81.2691%;">Array mit `1` bis `100` Gastobjekten. Jedes Objekt verwendet Schlüssel aus `metadata.guest`.</td></tr></tbody></table>

Vollständiges Beispiel für `push.json` aus dem Swagger-Modell `pushBody`:

```json
{
  "meta": {
    "failIfExists": false,
    "insertAs": 2
  },
  "guests": [
    {
      "GUEST_TICKET_CODE": "ABC123",
      "GUEST_FIRST_NAME": "Max",
      "GUEST_LAST_NAME": "Mustermann",
      "GUEST_EMAIL": "max@example.com",
      "gates": [
        1,
        3
      ]
    },
    {
      "GUEST_FIRST_NAME": "Simone",
      "GUEST_LAST_NAME": "Pfeifer",
      "GUEST_EMAIL": "simone@example.com"
    }
  ]
}

```

Die benutzerdefinierten Namens- und E-Mail-Felder sowie die Gate-IDs `1` und `3` sind Beispiele. Sie müssen in Ihren [Metadaten](https://doc.gwatch.events/books/externes-api/page/abruf-der-metadaten-metadata) vorkommen. Wenn keine Gate-Zuordnung geändert werden soll, lassen Sie `gates` weg.

**Feldnamen aus den Metadaten übernehmen:** In der geprüften Testveranstaltung heißen die Namensfelder beispielsweise `GUEST_VORNAME` und `GUEST_NACHNAME`, während das Swagger-Beispiel `GUEST_FIRST_NAME` und `GUEST_LAST_NAME` verwendet. Diese Namen sind nicht automatisch austauschbar. Maßgeblich ist die `key`-Angabe Ihrer tatsächlichen `metadata`-Antwort.

## Neuanlage oder Aktualisierung?

<table id="bkmrk-situation-verarbeitu"><thead><tr><th>Situation</th><th>Verarbeitung</th></tr></thead><tbody><tr><td>Ticketcode fehlt</td><td>Das Portal erzeugt einen neuen Code und legt einen Gast an.</td></tr><tr><td>Ticketcode vorhanden, aber kein bestehender Gast mit diesem Code gefunden</td><td>Ein neuer Gast wird mit diesem Code angelegt, sofern die Validierung erfolgreich ist.</td></tr><tr><td>Ticketcode gefunden und `failIfExists=false`</td><td>Der vorhandene Gast wird aktualisiert.</td></tr><tr><td>Ticketcode gefunden und `failIfExists=true`</td><td>Der Datensatz schlägt fehl; es wird kein zweiter Gast mit diesem Code angelegt.</td></tr></tbody></table>

Die Zuordnung erfolgt über den Ticketcode innerhalb der Veranstaltung, nicht über E-Mail-Adresse, Name oder die Datenbank-ID. Übermitteln Sie den Ticketcode als Zeichenfolge. Er muss den Restriktionen aus `metadata` entsprechen.

Bei einem Update werden die gesendeten Felder verarbeitet. **Weglassen und `null` sind nicht dasselbe:** Weggelassene Felder werden nicht gezielt überschrieben; ein ausdrücklich übergebenes `null` kann bei zulässigen Feldern einen Wert leeren. Bei `nullable=false` ist `null` ungültig. Prüfen Sie beabsichtigtes Leeren je Feldtyp zunächst mit Testdaten.

`insertAs` setzt keinen bestehenden Gast nachträglich auf einen anderen Teilnahmestatus. Dafür ist dieser Parameter nicht vorgesehen.

## Gate-Zuordnungen bewusst ersetzen

<table id="bkmrk-inhalt-im-gastobjekt"><thead><tr><th>Inhalt im Gastobjekt</th><th>Wirkung nach erfolgreicher Gastverarbeitung</th></tr></thead><tbody><tr><td>Kein `gates`-Schlüssel</td><td>Vorhandene Zuordnungen bleiben erhalten.</td></tr><tr><td>`"gates": [6398, 6399]`</td><td>Die Auswahl wird durch diese IDs ersetzt. Bereits zugeordnete Gates, die fehlen, werden entfernt.</td></tr><tr><td>`"gates": []`</td><td>Alle vorhandenen Gate-Zuordnungen werden entfernt.</td></tr></tbody></table>

Verwenden Sie ausschließlich freigegebene Gate-IDs aus `metadata.gates`. Wenn dort keine Gates verfügbar sind, lassen Sie den Schlüssel weg; im aktuellen API-Verhalten ist er dann kein freigegebenes Eingabefeld.

**Die Ersetzung betrifft auch vorhandene Zuordnungen, die in Ihrer übermittelten Auswahl nicht vorkommen.** Sie ist kein reines Hinzufügen. Soll nur ein Gate ergänzt werden, muss die vollständige gewünschte Auswahl abgestimmt sein. Eine Gate-Zuordnung über `push` ist kein Ein- oder Ausgangsscan.

## Antwort und Einzelergebnisse

Bei verarbeiteten Anfragen enthält die Antwort `summary` und `results`, ohne zusätzliches oberstes `error`-Feld.

<table id="bkmrk-feld-bedeutung-summa"><thead><tr><th>Feld</th><th>Bedeutung</th></tr></thead><tbody><tr><td>`summary.total`</td><td>Zahl der übergebenen Gastobjekte.</td></tr><tr><td>`summary.created`</td><td>Zahl erfolgreich neu angelegter Gäste.</td></tr><tr><td>`summary.updated`</td><td>Zahl erfolgreich aktualisierter Gäste.</td></tr><tr><td>`summary.failed`</td><td>Zahl fehlgeschlagener Gastobjekte.</td></tr><tr><td>`results[].index`</td><td>Position in Ihrem Eingabearray, beginnend bei `0`.</td></tr><tr><td>`results[].status`</td><td>`created`, `updated` oder `failed`.</td></tr><tr><td>`results[].ticketCode` / `id`</td><td>Zugeordneter Ticketcode und Gast-ID; bei Fehlern gegebenenfalls `null`.</td></tr><tr><td>`results[].message`</td><td>Bei Erfolg `null`, bei Fehlern eine Zeichenfolge oder ein Objekt mit Feldmeldungen.</td></tr></tbody></table>

Beispiel einer erfolgreichen Verarbeitung mit HTTP 200 aus dem Swagger-Modell `pushSuccess` (eigenständiges Antwortbeispiel, keine Zuordnung zum obigen Request):

```json
{
  "summary": {
    "total": 2,
    "created": 1,
    "updated": 1,
    "failed": 0
  },
  "results": [
    {
      "index": 0,
      "ticketCode": "223344",
      "id": 3247987,
      "status": "updated",
      "message": null
    },
    {
      "index": 1,
      "ticketCode": "223323",
      "id": 2343234,
      "status": "created",
      "message": null
    }
  ]
}

```

### HTTP 207: Ergebnisse einzeln behandeln

Sobald mindestens ein Datensatz fehlschlägt, lautet der HTTP-Status **207**, auch wenn alle Datensätze fehlschlagen. Erfolgreiche Datensätze werden dadurch nicht insgesamt zurückgerollt.

Beispiel einer Anfrage mit einem erfolgreichen Update und einem nicht freigegebenen Eingabeschlüssel:

```json
{
  "summary": {"total": 2, "created": 0, "updated": 1, "failed": 1},
  "results": [
    {"index": 0, "ticketCode": "TEST0001", "id": 12345, "status": "updated", "message": null},
    {"index": 1, "ticketCode": null, "id": null, "status": "failed", "message": "The following keys are not available: TICKET_CODE"}
  ]
}

```

`TICKET_CODE` ist kein Ersatz für `GUEST_TICKET_CODE`. Nutzen Sie `index`, um Fehler eindeutig dem gesendeten Datensatz zuzuordnen; bei einem Fehler muss `ticketCode` nicht den ursprünglich übergebenen Wert enthalten.

### HTTP 422: Anfrage korrigieren

Fehlende Steuerparameter, ein unzulässiges `insertAs`, eine leere Gästeliste oder mehr als 100 Datensätze führen zur Ablehnung der äußeren Anfrage. Beispiel:

```json
{
  "error": true,
  "message": {"meta.insertAs": ["The value may not be greater than 2."]}
}

```

Der Meldungstext ist beispielhaft. Verwenden Sie Feldschlüssel und HTTP-Status für die Auswertung. Fehler innerhalb einzelner Gastobjekte werden dagegen in der Regel über `results` und HTTP 207 gemeldet. Senden Sie stets echte Gastobjekte; andere Array-Inhalte sind kein unterstütztes Eingabeformat.

## Wiederholungen und Teiländerungen

- Speichern Sie das Ergebnis einschließlich `index`, Ticketcode und ID.
- Wiederholen Sie eine fehlgeschlagene Anfrage ohne eigene Ticketcodes nicht blind: Bereits angelegte Gäste könnten erneut angelegt werden.
- Auch eine Fehlermeldung bei einem Update garantiert nicht, dass sämtliche Felder des Gastes unverändert geblieben sind. Die Speicherung vorhandener Gäste ist nicht als atomarer Gesamtvorgang abgesichert. Prüfen Sie den aktuellen Stand, bevor Sie korrigiert erneut senden.
- Korrigieren Sie fehlgeschlagene Datensätze gezielt. Ein Timeout auf Ihrer Seite beweist nicht, dass der Server nichts gespeichert hat.

## Häufige Fehler

<table id="bkmrk-problem-pr%C3%BCfung-http"><thead><tr><th>Problem</th><th>Prüfung</th></tr></thead><tbody><tr><td>HTTP 401</td><td>Hauptschlüssel, Archivstatus, allgemeinen IP-Filter und exakt passenden Import-Schlüssel prüfen.</td></tr><tr><td>Unbekannter Feldschlüssel</td><td>Aktuelle `metadata.guest` verwenden, nicht die frei vereinbarten Lesefelder.</td></tr><tr><td>Listenwert abgewiesen</td><td>`items[].key` senden, nicht `value` oder `values`.</td></tr><tr><td>Bild wird abgewiesen</td><td>Gültige eingebettete Bild-Data-URI und freigegebenes Bildfeld prüfen.</td></tr><tr><td>Gate-ID ungültig</td><td>ID muss für diese Veranstaltung in `metadata.gates` vorkommen.</td></tr><tr><td>Bestehender Gast abgewiesen</td><td>`failIfExists` prüfen. Nur bei gewolltem Update auf `false` setzen.</td></tr><tr><td>Werte nach Update unerwartet leer</td><td>Gesendete `null`- oder Leerwerte prüfen. Unveränderte Felder weglassen.</td></tr><tr><td>Alte Gate-Zuordnungen fehlen</td><td>`gates` ersetzt die gesamte Auswahl. Vollständige gewünschte Zuordnung abstimmen.</td></tr></tbody></table>

## Vor dem produktiven Einsatz prüfen

1. Veranstaltung und Feldliste über `metadata` bestätigen.
2. Einen Testgast anlegen und zurückgegebenen Ticketcode speichern.
3. Denselben Gast mit `failIfExists=false` gezielt aktualisieren.
4. Fehlerfall mit `failIfExists=true` sowie Feldvalidierung prüfen.
5. Gate-Ersetzung nur mit abgestimmten Testzuordnungen testen.
6. Antwortauswertung für HTTP 200, 207, 401 und 422 vorsehen.

**Zurück:** [Einzelabruf](https://doc.gwatch.events/books/externes-api/page/abruf-von-daten-eines-einzelnen-gastes-fetch).  
**Zum Einstieg:** [Übersicht](https://doc.gwatch.events/books/externes-api/page/ubersicht).