> ## Documentation Index
> Fetch the complete documentation index at: https://docs.querying.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Ergebnis-Export nach Amazon S3, Google Cloud Storage und BigQuery

> Erhalten Sie jeden abgeschlossenen Task und jede bewertete Monitor-Antwort als stündliche oder tägliche JSON-Lines-Dateien im eigenen Bucket oder als Partitionen einer BigQuery-Tabelle.

Jede Stunde oder jeden UTC-Tag schreibt ein Export die Ergebnisse des Zeitfensters als gzip-komprimiertes JSON Lines in
einen Amazon-S3- oder Google-Cloud-Storage-Bucket oder lädt sie in eine Partition einer BigQuery-Tabelle. Ihr
Data Warehouse liest sie wie jede andere Quelle, ganz ohne Polling-Schleife.

Sie geben unserer Export-Identität Schreibrechte auf den Bucket oder das Dataset; Schlüssel oder Passwörter
teilen Sie nie. Alle Schlüssel, Buckets, Konto-IDs und Rollen auf dieser Seite sind Platzhalter.

## Was exportiert wird

| Datensatz | Zeilen | Zeitfenster nach | Gleiche Felder wie |
| - | - | - | - |
| `tasks` | Jeder Task des Kontos, der als `COMPLETED` oder `FAILED` endete | `completedAt` | [`GET /v1/async/task/{id}`](/de/api-reference/get-task) und der Webhook |
| `monitor_results` | Jede bewertete Antwort jedes Monitors des Kontos | `ranAt` | [`GET /v1/monitors/{id}/results?includeEvidence=true`](/de/api-reference/monitors/export-results) |

Tasks, die mit einem beliebigen Schlüssel des Kontos, aus dem Playground oder von Monitoren gesendet wurden, sind alle
enthalten. Ein Zeitfenster enthält genau die Zeilen, deren Zeitpunkt in `[windowStart, windowEnd)` liegt.

**Lieferzeitpunkt.** Ein Zeitfenster ist 10 Minuten nach seinem Ende fällig, damit an der Grenze abgerechnete
Gebühren enthalten sind. Fällige Zeitfenster holt ein Job ab, der alle 15 Minuten läuft; die Lieferung
beginnt daher normalerweise 10 bis 25 Minuten nach dem Ende des Zeitfensters.

## Export einrichten

**1. Export-Identität abrufen**

```bash theme={"theme":"css-variables"}
curl https://api.querying.ai/v1/exports/identity \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

```json theme={"theme":"css-variables"}
{
  "success": true,
  "identity": {
    "accountKey": "acct_3f9a1c2b7d4e",
    "gcp": { "serviceAccount": "querying-export@example-project.iam.gserviceaccount.com" },
    "aws": {
      "federatedPrincipal": "accounts.google.com",
      "audience": "117000000000000000001",
      "oaud": "querying-result-export",
      "roleSessionName": "querying-acct_3f9a1c2b7d4e",
      "trustPolicy": { "Version": "2012-10-17", "Statement": ["..."] }
    }
  }
}
```

`accountKey` benennt Ihren Ordner und Ihre Tabellen. Jeder Pfad und jede Tabelle, die wir schreiben, trägt
ihn, sodass mehrere querying.ai-Konten einen Bucket oder ein Dataset teilen können und jedes
nur seine eigenen Dateien schreibt. Berechtigen Sie die Identität aus Ihrer Antwort, nicht den Platzhalter oben.

**2. Zugriff gewähren**

Gewähren Sie der Identität Zugriff auf Ihr Ziel. Siehe
[Zugriff gewähren](#zugriff-gewähren) für S3, Cloud Storage und BigQuery.

**3. Export erstellen**

`POST /v1/exports` prüft die Berechtigung und speichert den Export. Siehe
[Export erstellen](#export-erstellen).

**4. Erste Lieferung beobachten**

`GET /v1/exports/{id}/runs` listet jedes Zeitfenster und seinen Status. Siehe
[Lieferverlauf](#lieferverlauf).

## Zugriff gewähren

### Amazon S3

Legen Sie in Ihrem AWS-Konto eine IAM-Rolle an, die unsere Google-Identität übernehmen kann. Verwenden Sie die
`trustPolicy` aus der Identitätsantwort als Vertrauensrichtlinie der Rolle. Sie akzeptiert nur unsere
Export-Identität und nur mit dem Sitzungsnamen Ihres Kontos:

```json theme={"theme":"css-variables"}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "accounts.google.com" },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": { "StringEquals": {
      "accounts.google.com:aud": "117000000000000000001",
      "accounts.google.com:oaud": "querying-result-export",
      "sts:RoleSessionName": "querying-acct_3f9a1c2b7d4e"
    } }
  }]
}
```

Hängen Sie eine Berechtigungsrichtlinie an, mit der die Rolle unter Ihrem Präfix schreiben darf:

```json theme={"theme":"css-variables"}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::acme-geo/querying/*"
  }]
}
```

Verschlüsselt der Bucket mit einem kundenverwalteten KMS-Schlüssel, erlauben Sie zusätzlich `kms:GenerateDataKey` für
diesen Schlüssel.

### Google Cloud Storage

Weisen Sie dem Export-Dienstkonto **Storage Object User** (`roles/storage.objectUser`) für
den Bucket zu. Damit legt es die Dateien an und ersetzt sie, wenn ein Zeitfenster erneut gesendet wird.

```bash theme={"theme":"css-variables"}
gcloud storage buckets add-iam-policy-binding gs://acme-geo \
  --member="serviceAccount:querying-export@example-project.iam.gserviceaccount.com" \
  --role="roles/storage.objectUser"
```

Um die Berechtigung auf Ihren Ordner zu beschränken, fügen Sie eine IAM-Bedingung auf
`resource.name.startsWith("projects/_/buckets/acme-geo/objects/querying/acct_3f9a1c2b7d4e/")` hinzu.

### BigQuery

Weisen Sie dem Export-Dienstkonto **BigQuery Data Editor** (`roles/bigquery.dataEditor`) für
das Dataset zu. Die Ladejobs laufen in unserem eigenen Projekt, das Laden kostet Sie also nichts; Sie zahlen
nur für Speicher und die Abfragen, die Sie ausführen.

```bash theme={"theme":"css-variables"}
bq add-iam-policy-binding \
  --member="serviceAccount:querying-export@example-project.iam.gserviceaccount.com" \
  --role="roles/bigquery.dataEditor" acme-analytics:geo_raw
```

## Export erstellen

Verwenden Sie einen API-Schlüssel ohne Engine-Beschränkung: Ein Export enthält jedes Ergebnis des Kontos, daher
erhält ein auf einige Engines beschränkter Schlüssel `403 KEY_SCOPE`.

```bash Amazon S3 theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/exports \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": {
      "type": "s3",
      "bucket": "acme-geo",
      "region": "us-east-1",
      "roleArn": "arn:aws:iam::123456789012:role/querying-export",
      "prefix": "querying"
    },
    "interval": "daily",
    "data": ["tasks", "monitor_results"]
  }'
```

```bash Google Cloud Storage theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/exports \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": { "type": "gcs", "bucket": "acme-geo", "prefix": "querying" },
    "interval": "hourly",
    "data": ["tasks"]
  }'
```

```bash BigQuery theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/exports \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": { "type": "bigquery", "projectId": "acme-analytics", "datasetId": "geo_raw" },
    "interval": "daily",
    "startAt": "2026-10-01T00:00:00Z"
  }'
```

| Feld | Pflicht | Beschreibung |
| - | - | - |
| `destination.type` | Ja | `s3`, `gcs` oder `bigquery`. |
| `destination.bucket` | S3, GCS | Der Bucket-Name. |
| `destination.prefix` | Nein | Ordner im Bucket, bis zu 256 Zeichen, relativ (kein führendes `/`, keine `.`- oder `..`-Segmente). Ein abschließendes `/` wird ergänzt. |
| `destination.region` | S3 | Die AWS-Region des Buckets, etwa `us-east-1`. |
| `destination.roleArn` | S3 | Die Rolle aus [Zugriff gewähren](#amazon-s3), `arn:aws:iam::<account>:role/<name>`. |
| `destination.projectId`, `destination.datasetId` | BigQuery | Das Google-Cloud-Projekt und das Dataset. |
| `interval` | Nein | `hourly` oder `daily` (Standard). Für die gesamte Lebensdauer des Exports fest. |
| `data` | Nein | `tasks`, `monitor_results` oder beide (Standard). |
| `startAt` | Nein | ISO-8601-Zeitpunkt, nicht in der Zukunft und höchstens 30 Tage zurück. Das erste Zeitfenster ist das, das ihn enthält. Standard: jetzt. |

Vor dem Speichern prüft der Export die Berechtigung. Für S3 und Cloud Storage schreibt er
`<prefix><accountKey>/_querying/connection-check.json`; für BigQuery liest er das Dataset
und speichert dessen Standort. Schlägt die Prüfung fehl, wird nichts gespeichert. Ein Konto kann bis zu 10
Exporte haben.

Die Antwort ist `201` mit dem Export:

```json theme={"theme":"css-variables"}
{
  "success": true,
  "export": {
    "id": "6a1d0f3c-...",
    "destination": {
      "type": "bigquery",
      "projectId": "acme-analytics",
      "datasetId": "geo_raw",
      "location": "US",
      "tables": [
        "acme-analytics.geo_raw.querying_tasks_v1_acct_3f9a1c2b7d4e",
        "acme-analytics.geo_raw.querying_monitor_results_v1_acct_3f9a1c2b7d4e"
      ]
    },
    "interval": "daily",
    "data": ["tasks", "monitor_results"],
    "enabled": true,
    "schemaVersion": 1,
    "nextWindowStart": "2026-10-01T00:00:00.000Z",
    "createdAt": "2026-10-19T09:00:00.000Z",
    "deliveredThrough": null,
    "failedRuns": 0,
    "retryingRuns": 0
  }
}
```

Für S3 und Cloud Storage gibt `destination` die Bucket-Einstellungen zurück und ergänzt `path`, den
Ordner, in dem Ihre Dateien landen, etwa `s3://acme-geo/querying/acct_3f9a1c2b7d4e/` oder
`gs://acme-geo/querying/acct_3f9a1c2b7d4e/`. `nextWindowStart` ist der Beginn des nächsten
zu planenden Zeitfensters.

### Fehler

| Status | Code | Ursache |
| - | - | - |
| `400` | `VALIDATION_ERROR` | Ungültiges JSON oder ein Feld außerhalb des zulässigen Bereichs. Die Meldung nennt das Feld, etwa `destination.region: region is the bucket's AWS region, e.g. us-east-1`. |
| `403` | `KEY_SCOPE` | Der API-Schlüssel ist auf einige Engines beschränkt. |
| `409` | `EXPORT_LIMIT` | Das Konto hat bereits 10 Exporte. |
| `422` | `EXPORT_DESTINATION_UNREACHABLE` | Die Verbindungsprüfung ist fehlgeschlagen. Die Meldung enthält den Grund des Speicheranbieters, meist eine fehlende Berechtigung. |
| `502` | `EXPORT_CHECK_FAILED` | Das Ziel war nicht erreichbar. Versuchen Sie es erneut. |
| `503` | `EXPORTS_NOT_CONFIGURED` | Exporte zu diesem Zieltyp sind nicht verfügbar. |

## Dateien und Tabellen

### Dateien in S3 und Cloud Storage

```text theme={"theme":"css-variables"}
s3://acme-geo/querying/acct_3f9a1c2b7d4e/tasks/v1/dt=2026-10-08/part-00000.jsonl.gz
s3://acme-geo/querying/acct_3f9a1c2b7d4e/tasks/v1/dt=2026-10-08/_manifest.json
s3://acme-geo/querying/acct_3f9a1c2b7d4e/monitor_results/v1/dt=2026-10-08/hour=13/part-00000.jsonl.gz
```

* Die Verzeichnisse folgen der Hive-Partitionierung (`dt=` und bei stündlichen Exporten `hour=`), sodass Athena,
  externe BigQuery-Tabellen und Spark sie als Spalten lesen.
* `v1` ist die Schemaversion (`schemaVersion` des Exports). Eine Änderung, die eine Spalte bricht,
  erscheint als `v2` daneben.
* Ein Zeitfenster wird in Teile mit bis zu 100.000 Zeilen aufgeteilt, in zeitlicher Reihenfolge.
* `_manifest.json` wird zuletzt geschrieben. Laden Sie ein Zeitfenster, sobald sein Manifest existiert, und lesen Sie die
  Liste der Teile daraus:

```json theme={"theme":"css-variables"}
{
  "schemaVersion": 1,
  "data": "tasks",
  "windowStart": "2026-10-08T00:00:00.000Z",
  "windowEnd": "2026-10-09T00:00:00.000Z",
  "rows": 20000,
  "files": [{ "key": "querying/acct_3f9a1c2b7d4e/tasks/v1/dt=2026-10-08/part-00000.jsonl.gz", "rows": 20000, "bytes": 1990096 }],
  "deliveredAt": "2026-10-09T00:16:02.114Z"
}
```

`rows` im Manifest entspricht der Zeilenzahl seiner Teile und dem `rows` des Laufs im
Lieferverlauf. Dateinamen hängen nur vom Zeitfenster ab, daher ersetzt ein erneut gesendetes Zeitfenster dieselben
Objekte.

### BigQuery-Tabellen

BigQuery-Exporte laden in `querying_tasks_v1_<accountKey>` und
`querying_monitor_results_v1_<accountKey>`, die beim ersten Laden angelegt und nach
`completedAt` bzw. `ranAt` partitioniert werden (nach Tag, bei stündlichen Exporten nach Stunde). Jedes Zeitfenster ersetzt seine
eigene Partition, daher verdoppelt sich ein erneut gesendetes Zeitfenster nie. `payload`, `response`, `sources` und
`scoringContext` sind `JSON`-Spalten:

```sql theme={"theme":"css-variables"}
SELECT taskType, JSON_VALUE(payload.prompt) AS prompt, JSON_VALUE(response.text) AS answer
FROM `acme-analytics.geo_raw.querying_tasks_v1_acct_3f9a1c2b7d4e`
WHERE DATE(completedAt) = "2026-10-08" AND status = "COMPLETED";
```

## Zeilenschema (v1)

### `tasks`

| Feld | Typ | BigQuery-Typ | Beschreibung |
| - | - | - | - |
| `id` | string | `STRING` | Task-ID. |
| `taskType` | string | `STRING` | Engine, etwa `CHATGPT`. |
| `status` | string | `STRING` | `COMPLETED` oder `FAILED`. |
| `priority` | integer | `INT64` | Wie eingereicht. |
| `idempotencyKey` | string oder null | `STRING` | Ihr Schlüssel, falls Sie einen gesendet haben. |
| `createdAt`, `completedAt` | timestamp | `TIMESTAMP` | UTC, mikrosekundengenau. |
| `monitorId` | string oder null | `STRING` | Der Monitor, der sie ausgeführt hat. |
| `creditsCharged` | decimal | `NUMERIC` | Für den Task berechnete Credits, mit bis zu zwei Dezimalstellen (zum Beispiel `1.25`). `0` bei einem fehlgeschlagenen Task. Lesen Sie den Wert als Dezimalzahl, nicht als Ganzzahl. |
| `payload` | object | `JSON` | Der Payload wie eingereicht. |
| `response` | object oder null | `JSON` | Das Ergebnis, wie `GET /v1/async/task/{id}` es liefert; `null`, wenn der Task fehlgeschlagen ist. |
| `error` | string oder null | `STRING` | Der Fehlergrund, beginnend mit seinem Code; `null` bei abgeschlossenen Tasks. |

### `monitor_results`

| Feld | Typ | BigQuery-Typ | Beschreibung |
| - | - | - | - |
| `id`, `monitorId`, `taskId` | string | `STRING` | IDs von Ergebnis, Monitor und Task. |
| `engine`, `prompt` | string | `STRING` | Was wo gefragt wurde. |
| `mentioned`, `cited` | boolean | `BOOL` | Marke genannt; Ihre Domain zitiert. |
| `position` | integer oder null | `INT64` | Zeichenposition der ersten Markenerwähnung. |
| `competitorHits` | string array | `STRING`, wiederholt | In der Antwort genannte Wettbewerber. |
| `sources` | array | `JSON` | Zitate als `{url, label, position}`. |
| `answerText` | string oder null | `STRING` | Die Antwort, aus der die Bewertung gelesen wurde. |
| `scoringContext` | object oder null | `JSON` | Die damalige Bewertungsdefinition. |
| `latitude`, `longitude` | number oder null | `FLOAT64` | Der Punkt, von dem aus gefragt wurde, bei Standort-Monitoren. |
| `ranAt` | timestamp | `TIMESTAMP` | UTC, mikrosekundengenau. |

## Lieferverlauf

Jedes Zeitfenster jedes Datensatzes ist ein Lauf. Listen Sie sie auf, neueste zuerst:

```bash theme={"theme":"css-variables"}
curl "https://api.querying.ai/v1/exports/$EXPORT_ID/runs?status=failed" \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

```json theme={"theme":"css-variables"}
{
  "success": true,
  "runs": [{
    "id": "3c9e1b7a-...",
    "data": "tasks",
    "windowStart": "2026-10-08T00:00:00.000Z",
    "windowEnd": "2026-10-09T00:00:00.000Z",
    "status": "failed",
    "attempts": 8,
    "nextAttemptAt": null,
    "rows": null,
    "bytes": null,
    "files": [],
    "error": "S3 PutObject s3://acme-geo/... failed: HTTP 403 AccessDenied: Access Denied",
    "deliveredAt": null
  }],
  "nextCursor": null
}
```

| `status` | Bedeutung |
| - | - |
| `pending` | Wartet auf die Lieferung oder nach einem fehlgeschlagenen Versuch auf die Wiederholung. `nextAttemptAt` sagt, wann. |
| `running` | Wird gerade geliefert. |
| `delivered` | Geschrieben. `rows`, `bytes`, `files` und `deliveredAt` sind gesetzt. |
| `failed` | Acht Versuche sind fehlgeschlagen. Es passiert nichts mehr, bis Sie ihn erneut senden. |

Filtern Sie mit `status`, `data` (`tasks` oder `monitor_results`) und `limit` (1–200, Standard
50\); geben Sie `nextCursor` als `cursor` zurück, um die nächste Seite zu erhalten.

* **Automatische Wiederholungen.** Ein fehlgeschlagener Versuch wird nach 15 Minuten wiederholt, danach mit sich
  verdoppelnder Wartezeit bis zu 12 Stunden, insgesamt acht Versuche. `error` enthält den Grund des
  Speicheranbieters; eine fehlende Berechtigung zeigt sich also zuerst hier.
* **Zeitfenster erneut senden.** `POST /v1/exports/{id}/runs/{runId}/retry` sendet ein Zeitfenster sofort: ein
  fehlgeschlagenes, nachdem Sie die Berechtigung korrigiert haben, oder ein geliefertes, das neu geschrieben werden soll. Es setzt
  `attempts` zurück und gibt den Lauf als `pending` zurück. Ein Lauf, der gerade geliefert wird, ergibt
  `409 EXPORT_RUN_RUNNING`.
* **Export-Zustand.** `GET /v1/exports` und `GET /v1/exports/{id}` ergänzen `deliveredThrough`
  (das Ende des zuletzt gelieferten Zeitfensters), `failedRuns` und `retryingRuns` (wartende Läufe,
  die bereits mindestens einmal fehlgeschlagen sind).

## Pausieren, fortsetzen und löschen

* `PATCH /v1/exports/{id}` mit `{"enabled": false}` pausiert einen Export. `{"enabled": true}`
  setzt ihn fort und holt die verpassten Zeitfenster nach, bis zu 30 Tage zurück.
* `DELETE /v1/exports/{id}` beendet den Export. Bereits gelieferte Dateien und Partitionen bleiben in
  Ihrem Speicher.
* Ziel, Intervall und Datensätze lassen sich nicht ändern. Erstellen Sie einen neuen Export und löschen Sie den
  alten.

## Endpunkte

| Methode und Pfad | Zweck |
| - | - |
| [`GET /v1/exports/identity`](/de/api-reference/exports/get-identity) | Die zu berechtigende Identität und Ihr Account-Key |
| [`POST /v1/exports`](/de/api-reference/exports/create-export) | Ein Ziel verbinden |
| [`GET /v1/exports`](/de/api-reference/exports/list-exports) | Exporte mit Lieferstatus auflisten |
| [`GET /v1/exports/{id}`](/de/api-reference/exports/get-export) | Ein Export |
| [`PATCH /v1/exports/{id}`](/de/api-reference/exports/update-export) | Pausieren oder fortsetzen |
| [`DELETE /v1/exports/{id}`](/de/api-reference/exports/delete-export) | Den Export beenden |
| [`GET /v1/exports/{id}/runs`](/de/api-reference/exports/list-runs) | Lieferverlauf |
| [`POST /v1/exports/{id}/runs/{runId}/retry`](/de/api-reference/exports/retry-run) | Ein Zeitfenster erneut senden |

Ein Export, der Ihnen nicht gehört, ergibt `404 NOT_FOUND`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.