# Asynchrone Ergebnisse (https://webmetic.de/docs/api/asynchrone-ergebnisse)

Zwei Enrichment-Aufrufe in der API arbeiten auf diese Weise. Zum Beispiel senden Sie 300 Domains aus Ihrer Messeliste an eine Enrichment-Liste. Die API bestätigt sofort mit HTTP 202, und Sie holen die Unternehmensdaten später ab.

Ein 202 ist also weder ein Fehler noch ein Auftrag mit Job-ID.

## Asynchrone Endpunkte [#asynchrone-endpunkte]

Nur zwei Endpunkte antworten mit 202, und beide gehören zu Enrichment:

- **Einzelabfrage**: [`GET /enrichment/company`](https://webmetic.de/docs/api/referenz/enrichment/company) liefert die Daten eines Unternehmens zu einer Domain.
- **Liste**: [`POST /enrichment/lists/{list_id}/domains`](https://webmetic.de/docs/api/referenz/enrichment/lists-list-id-domains) fügt einer Liste Domains hinzu, die Webmetic danach anreichert.

Alle anderen Endpunkte antworten sofort mit dem Ergebnis oder einem Fehler, auch die für Ansprechpartner unter `/contacts/*`.

Beide Aufrufe brauchen den Enrichment-Schlüssel, nicht den Schlüssel für Visitor Intelligence. Neue Listen, neue Domains und Einzelabfragen brauchen außerdem die Testphase, den Plan Growth oder den Plan Enterprise. Sonst antwortet die API mit 403 und `PLAN_REQUIRED`.

## Einzelabfrage [#einzelabfrage]

Wenn Webmetic die Domain schon kennt, antwortet die API sofort mit 200 und `"status": "found"`. Sonst beginnt Webmetic mit der Arbeit und antwortet mit 202:

```http
HTTP/1.1 202 Accepted
Retry-After: 15

{"status": "processing", "domain": "beispiel.de", "retry_after_seconds": 15}
```

Wiederholen Sie dann dieselbe Anfrage nach so vielen Sekunden, wie `retry_after_seconds` oder der Header `Retry-After` nennt. Eine Wiederholung startet keinen zweiten Lauf für dieselbe Domain.

Fragen Sie erneut, bis die API mit 200 und `found` oder mit 404 und `not_found` antwortet. Ein 404 heißt hier, dass die Website nicht erreichbar war oder keine verwertbaren Daten hatte.

Wenn Webmetic die Website erst lesen muss, dauert das Stunden bis einige Tage. Die API beendet die Einzelabfrage in dieser Zeit nicht von selbst. Geben Sie Ihrem Client deshalb eine eigene Höchstdauer, nach der er nicht mehr fragt.

Für unbekannte Domains empfehlen wir eine Liste, denn dort endet jede Zeile mit einem Ergebnis.

```bash tab="cURL" tab-group="lang"
curl -i "https://hub.webmetic.de/enrichment/company?domain=beispiel.de" \
  -H "Authorization: wmtc_IHR_API_SCHLUESSEL"
```

```js tab="JavaScript" tab-group="lang"
const url = 'https://hub.webmetic.de/enrichment/company?domain=beispiel.de';
const headers = { Authorization: 'wmtc_IHR_API_SCHLUESSEL' };
const deadline = Date.now() + 10 * 60 * 1000; // your own maximum wait

let res = await fetch(url, { headers });
while (res.status === 202 && Date.now() < deadline) {
  const { retry_after_seconds } = await res.json();
  await new Promise((resolve) => setTimeout(resolve, retry_after_seconds * 1000));
  res = await fetch(url, { headers });
}
const body = await res.json(); // 200 found, 404 not_found, or still 202
```

```python tab="Python" tab-group="lang"
import time
import requests

url = "https://hub.webmetic.de/enrichment/company"
params = {"domain": "beispiel.de"}
headers = {"Authorization": "wmtc_IHR_API_SCHLUESSEL"}
deadline = time.monotonic() + 10 * 60  # your own maximum wait

res = requests.get(url, params=params, headers=headers)
while res.status_code == 202 and time.monotonic() < deadline:
    time.sleep(res.json()["retry_after_seconds"])
    res = requests.get(url, params=params, headers=headers)
body = res.json()  # 200 found, 404 not_found, or still 202
```

## Ablauf einer Liste [#ablauf-einer-liste]

1. **Domains senden**: Die API antwortet mit 202 und zählt neue, vorhandene und ungültige Domains.
2. **Webmetic reichert an**: Jede neue Zeile startet als `pending` und wechselt zu `enriching`.
3. **Fortschritt abfragen**: Sie rufen die Liste ab, bis `pending_rows` 0 ist.
4. **Ergebnisse abholen**: Sie laden die Zeilen als JSON oder als CSV-Datei.

Die Liste selbst legen Sie vorher mit [`POST /enrichment/lists`](https://webmetic.de/docs/api/referenz/enrichment/lists-post) an, und die API antwortet darauf sofort mit 201. Danach senden Sie bis zu 5.000 Domains pro Anfrage:

```bash tab="cURL" tab-group="lang"
curl -X POST "https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID/domains" \
  -H "Authorization: wmtc_IHR_API_SCHLUESSEL" \
  -H "Content-Type: application/json" \
  -d '{"domains": ["beispiel.de", "muster-gmbh.de"]}'
```

```js tab="JavaScript" tab-group="lang"
const res = await fetch(
  'https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID/domains',
  {
    method: 'POST',
    headers: {
      Authorization: 'wmtc_IHR_API_SCHLUESSEL',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ domains: ['beispiel.de', 'muster-gmbh.de'] }),
  },
);
const result = await res.json(); // 202: added, skipped_existing, invalid, list_id
```

```python tab="Python" tab-group="lang"
import requests

res = requests.post(
    "https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID/domains",
    headers={"Authorization": "wmtc_IHR_API_SCHLUESSEL"},
    json={"domains": ["beispiel.de", "muster-gmbh.de"]},
)
result = res.json()  # 202: added, skipped_existing, invalid, list_id
```

`added` zählt die neuen Zeilen, `invalid` die Einträge ohne gültige Domain. `skipped_existing` zählt Domains, die schon in der Liste stehen und die Webmetic deshalb nicht erneut anreichert.

[`GET /enrichment/lists/{list_id}`](https://webmetic.de/docs/api/referenz/enrichment/lists-list-id) zeigt den Fortschritt mit drei Zählern:

- **`done_rows`**: Zeilen mit dem Status `done`.
- **`miss_rows`**: Zeilen mit dem Status `miss`.
- **`pending_rows`**: alle übrigen Zeilen, also `pending` und `enriching`.

Anders als die Einzelabfrage nennen die Listen-Endpunkte kein Abfrageintervall. Weil unbekannte Domains Stunden brauchen, genügen seltene Abfragen.

Wenn `pending_rows` auf 0 steht, ist jede Zeile der Liste fertig. Rufen Sie dann [`/rows`](https://webmetic.de/docs/api/referenz/enrichment/lists-list-id-rows) seitenweise mit `page` und `page_size` ab. Eine Seite umfasst standardmäßig und höchstens 10.000 Zeilen, und die Antwort enthält `rows`, `total` und `pagination`.

Der Filter `status` akzeptiert einen der vier Statuswerte, und `total` zählt dann nur die passenden Zeilen. [`/export`](https://webmetic.de/docs/api/referenz/enrichment/lists-list-id-export) liefert alle Zeilen auf einmal als CSV-Datei.

```bash tab="cURL" tab-group="lang"
curl "https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID" \
  -H "Authorization: wmtc_IHR_API_SCHLUESSEL"

curl "https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID/rows?status=done&page=1" \
  -H "Authorization: wmtc_IHR_API_SCHLUESSEL"
```

```js tab="JavaScript" tab-group="lang"
const base = 'https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID';
const headers = { Authorization: 'wmtc_IHR_API_SCHLUESSEL' };

const { list } = await (await fetch(base, { headers })).json();
if (list.pending_rows === 0) {
  const res = await fetch(`${base}/rows?status=done&page=1`, { headers });
  const { rows, pagination } = await res.json();
}
```

```python tab="Python" tab-group="lang"
import requests

base = "https://hub.webmetic.de/enrichment/lists/IHRE_LISTEN_ID"
headers = {"Authorization": "wmtc_IHR_API_SCHLUESSEL"}

list_info = requests.get(base, headers=headers).json()["list"]
if list_info["pending_rows"] == 0:
    res = requests.get(f"{base}/rows", params={"status": "done", "page": 1}, headers=headers)
    rows = res.json()["rows"]
```

## Zeilenstatus [#zeilenstatus]

Jede Zeile einer Liste hat einen von vier Statuswerten. Das Dashboard zeigt dieselben Zeilen mit eigenen Bezeichnungen:

| Status | Bedeutung | Im Dashboard |
| --- | --- | --- |
| `pending` | Die Zeile wartet auf die Bearbeitung | **Enriching** |
| `enriching` | Webmetic reichert die Zeile gerade an | **Enriching** |
| `done` | Webmetic hat Daten gefunden | **Enriched** |
| `miss` | Webmetic hat keine verwertbaren Daten gefunden | **Nicht gefunden** |

[Enrichment-Liste](https://webmetic.de/docs/api/datenmodell/enrichment-liste) beschreibt alle Felder einer Zeile.

`done` und `miss` sind endgültig. Solange Webmetic die Website noch lesen muss, kann eine Zeile von `enriching` zurück auf `pending` wechseln.

- **Teilweise gefüllt**: Weil Webmetic die Felder einer Zeile nacheinander schreibt, zeigen `/rows` und `/export` vor dem Ende auch halb gefüllte Zeilen.
- **Leere Felder**: Auch eine Zeile mit `done` kann leere Felder haben, wenn Webmetic einen Wert nicht kennt. In `/rows` stehen diese Felder als `null`.
- **Dashboard**: Listen aus der API erscheinen im Tab **Enrichment**, Einzelabfragen dagegen nicht.

## Credits und Webhooks [#credits-und-webhooks]

Das Abfragen des Status kostet keine Credits, weder die Wiederholung der Einzelabfrage noch der Abruf von Liste, Zeilen und Export.

Enrichment kostet derzeit keine Credits. Mehr dazu unter [Credits in der API](https://webmetic.de/docs/api/credits).

Webmetic sendet für Enrichment-Ergebnisse kein Webhook-Ereignis, denn [Webhooks](https://webmetic.de/docs/api/webhooks) melden nur Besuche von Unternehmen auf Ihrer Website. Deshalb fragen Sie den Fortschritt einer Liste selbst ab.

## Nächste Schritte [#nächste-schritte]

- [Paginierung](https://webmetic.de/docs/api/paginierung): Die Zeilen einer großen Liste seitenweise abrufen.
- [Fehler](https://webmetic.de/docs/api/fehler): Fehlercodes wie `PLAN_REQUIRED` verstehen und beheben.
- [Enrichment](https://webmetic.de/docs/enrichment): Listen im Dashboard anlegen, verfolgen und exportieren.
