> ## 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.

# Export des résultats vers Amazon S3, Google Cloud Storage et BigQuery

> Recevez chaque tâche terminée et chaque réponse notée des moniteurs sous forme de fichiers JSON Lines horaires ou quotidiens dans votre propre bucket, ou de partitions d’une table BigQuery.

Chaque heure ou chaque jour UTC, un export écrit les résultats de la fenêtre en JSON Lines compressé gzip dans
un bucket Amazon S3 ou Google Cloud Storage, ou les charge dans une partition d'une table BigQuery. Votre
entrepôt de données les lit comme n'importe quelle autre source, sans boucle de polling.

Vous accordez à notre identité d'export un droit d'écriture sur le bucket ou le dataset ; vous ne partagez jamais
de clés ni de mots de passe. Les clés, buckets, identifiants de compte et rôles de cette page sont des exemples.

## Ce qui est exporté

| Jeu de données | Lignes | Fenêtre selon | Mêmes champs que |
| - | - | - | - |
| `tasks` | Chaque tâche du compte terminée en `COMPLETED` ou `FAILED` | `completedAt` | [`GET /v1/async/task/{id}`](/fr/api-reference/get-task) et le webhook |
| `monitor_results` | Chaque réponse notée de chaque moniteur du compte | `ranAt` | [`GET /v1/monitors/{id}/results?includeEvidence=true`](/fr/api-reference/monitors/export-results) |

Les tâches envoyées avec n'importe quelle clé du compte, depuis le Playground et par les moniteurs sont toutes
incluses. Une fenêtre contient exactement les lignes dont l'heure tombe dans `[windowStart, windowEnd)`.

**Délai de livraison.** Une fenêtre est due 10 minutes après sa fermeture, afin que les facturations réglées à la
limite y figurent. Les fenêtres dues sont prises en charge par un job qui s'exécute toutes les 15 minutes : la
livraison commence donc normalement 10 à 25 minutes après la fermeture de la fenêtre.

## Configurer un export

**1. Lire votre identité d’export**

```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` nomme votre dossier et vos tables. Chaque chemin et chaque table que nous écrivons le porte :
plusieurs comptes querying.ai peuvent partager un bucket ou un dataset, et chacun n'écrit
que ses propres fichiers. Autorisez l'identité que montre votre réponse, pas l'exemple ci-dessus.

**2. Accorder l’accès**

Accordez l'accès à votre destination à cette identité. Voir
[Accorder l'accès](#accorder-l’accès) pour S3, Cloud Storage et BigQuery.

**3. Créer l’export**

`POST /v1/exports` vérifie l'autorisation et enregistre l'export. Voir
[Créer l'export](#créer-l’export).

**4. Surveiller la première livraison**

`GET /v1/exports/{id}/runs` liste chaque fenêtre et son statut. Voir
[Historique de livraison](#historique-de-livraison).

## Accorder l'accès

### Amazon S3

Créez dans votre compte AWS un rôle IAM que notre identité Google peut assumer. Utilisez le
`trustPolicy` de la réponse d'identité comme politique d'approbation du rôle. Il n'accepte que notre
identité d'export, et seulement avec le nom de session de votre compte :

```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"
    } }
  }]
}
```

Attachez une politique d'autorisation qui permet au rôle d'écrire sous votre préfixe :

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

Si le bucket chiffre avec une clé KMS gérée par le client, autorisez aussi `kms:GenerateDataKey` sur
cette clé.

### Google Cloud Storage

Accordez au compte de service d'export le rôle **Storage Object User** (`roles/storage.objectUser`) sur
le bucket. Il crée les fichiers et les remplace quand une fenêtre est renvoyée.

```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"
```

Pour limiter l'accès à votre dossier, ajoutez une condition IAM sur
`resource.name.startsWith("projects/_/buckets/acme-geo/objects/querying/acct_3f9a1c2b7d4e/")`.

### BigQuery

Accordez au compte de service d'export le rôle **BigQuery Data Editor** (`roles/bigquery.dataEditor`) sur
le dataset. Nous exécutons les jobs de chargement dans notre propre projet : le chargement ne vous coûte rien, vous
ne payez que le stockage et vos requêtes.

```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
```

## Créer l'export

Utilisez une clé d'API sans restriction de moteurs : un export transporte tous les résultats du compte, donc une
clé limitée à certains moteurs reçoit `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"
  }'
```

| Champ | Obligatoire | Description |
| - | - | - |
| `destination.type` | Oui | `s3`, `gcs` ou `bigquery`. |
| `destination.bucket` | S3, GCS | Le nom du bucket. |
| `destination.prefix` | Non | Dossier dans le bucket, jusqu'à 256 caractères, relatif (pas de `/` initial, pas de segments `.` ou `..`). Un `/` final est ajouté. |
| `destination.region` | S3 | La région AWS du bucket, par exemple `us-east-1`. |
| `destination.roleArn` | S3 | Le rôle de [Accorder l'accès](#amazon-s3), `arn:aws:iam::<account>:role/<name>`. |
| `destination.projectId`, `destination.datasetId` | BigQuery | Le projet et le dataset Google Cloud. |
| `interval` | Non | `hourly` ou `daily` (par défaut). Fixé pour toute la vie de l'export. |
| `data` | Non | `tasks`, `monitor_results` ou les deux (par défaut). |
| `startAt` | Non | Heure ISO 8601, pas dans le futur et au plus 30 jours en arrière. La première fenêtre est celle qui la contient. Par défaut : maintenant. |

Avant d'enregistrer, l'export vérifie l'autorisation. Pour S3 et Cloud Storage, il écrit
`<prefix><accountKey>/_querying/connection-check.json` ; pour BigQuery, il lit le dataset
et enregistre sa localisation. Si la vérification échoue, rien n'est enregistré. Un compte peut avoir jusqu'à 10
exports.

La réponse est `201` avec l'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
  }
}
```

Pour S3 et Cloud Storage, `destination` reprend les réglages du bucket et ajoute `path`, le
dossier où arrivent vos fichiers, par exemple `s3://acme-geo/querying/acct_3f9a1c2b7d4e/` ou
`gs://acme-geo/querying/acct_3f9a1c2b7d4e/`. `nextWindowStart` est le début de la prochaine
fenêtre à planifier.

### Erreurs

| Statut | Code | Cause |
| - | - | - |
| `400` | `VALIDATION_ERROR` | JSON invalide ou champ hors limites. Le message nomme le champ, par exemple `destination.region: region is the bucket's AWS region, e.g. us-east-1`. |
| `403` | `KEY_SCOPE` | La clé d'API est limitée à certains moteurs. |
| `409` | `EXPORT_LIMIT` | Le compte a déjà 10 exports. |
| `422` | `EXPORT_DESTINATION_UNREACHABLE` | La vérification de connexion a échoué. Le message contient la raison donnée par le fournisseur de stockage, en général une autorisation manquante. |
| `502` | `EXPORT_CHECK_FAILED` | La destination est injoignable. Réessayez. |
| `503` | `EXPORTS_NOT_CONFIGURED` | Les exports vers ce type de destination ne sont pas disponibles. |

## Fichiers et tables

### Fichiers dans S3 et 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
```

* Les répertoires suivent le partitionnement Hive (`dt=`, et `hour=` pour les exports horaires) : Athena,
  les tables externes BigQuery et Spark les lisent comme des colonnes.
* `v1` est la version du schéma (`schemaVersion` de l'export). Un changement qui casse une colonne
  est publié en `v2` à côté.
* Une fenêtre est découpée en parties de 100 000 lignes au plus, dans l'ordre chronologique.
* `_manifest.json` est écrit en dernier. Chargez une fenêtre dès que son manifeste existe et lisez-y
  la liste des parties :

```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` dans le manifeste est égal au nombre de lignes de ses parties et au `rows` de l'exécution dans
l'historique de livraison. Les noms de fichiers ne dépendent que de la fenêtre : une fenêtre renvoyée remplace
les mêmes objets.

### Tables BigQuery

Les exports BigQuery chargent dans `querying_tasks_v1_<accountKey>` et
`querying_monitor_results_v1_<accountKey>`, créées au premier chargement et partitionnées par
`completedAt` ou `ranAt` (par jour, ou par heure pour les exports horaires). Chaque fenêtre remplace sa
propre partition : une fenêtre renvoyée n'est jamais dupliquée. `payload`, `response`, `sources` et
`scoringContext` sont des colonnes `JSON` :

```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";
```

## Schéma des lignes (v1)

### `tasks`

| Champ | Type | Type BigQuery | Description |
| - | - | - | - |
| `id` | string | `STRING` | Identifiant de la tâche. |
| `taskType` | string | `STRING` | Moteur, par exemple `CHATGPT`. |
| `status` | string | `STRING` | `COMPLETED` ou `FAILED`. |
| `priority` | integer | `INT64` | Tel qu'envoyé. |
| `idempotencyKey` | string ou null | `STRING` | Votre clé, si vous en avez envoyé une. |
| `createdAt`, `completedAt` | timestamp | `TIMESTAMP` | UTC, précision à la microseconde. |
| `monitorId` | string ou null | `STRING` | Le moniteur qui l'a lancée. |
| `creditsCharged` | decimal | `NUMERIC` | Crédits facturés pour la tâche, avec jusqu'à deux décimales (par exemple `1.25`). `0` pour une tâche en échec. Lisez-le comme un décimal, pas comme un entier. |
| `payload` | object | `JSON` | Le payload tel qu'envoyé. |
| `response` | object ou null | `JSON` | Le résultat tel que `GET /v1/async/task/{id}` le renvoie ; `null` si la tâche a échoué. |
| `error` | string ou null | `STRING` | La raison de l'échec, qui commence par son code ; `null` si terminée. |

### `monitor_results`

| Champ | Type | Type BigQuery | Description |
| - | - | - | - |
| `id`, `monitorId`, `taskId` | string | `STRING` | Identifiants du résultat, du moniteur et de la tâche. |
| `engine`, `prompt` | string | `STRING` | Ce qui a été demandé et où. |
| `mentioned`, `cited` | boolean | `BOOL` | Marque nommée ; votre domaine cité. |
| `position` | integer ou null | `INT64` | Position en caractères de la première mention de la marque. |
| `competitorHits` | string array | `STRING`, répété | Concurrents nommés dans la réponse. |
| `sources` | array | `JSON` | Citations sous la forme `{url, label, position}`. |
| `answerText` | string ou null | `STRING` | La réponse dont la note est tirée. |
| `scoringContext` | object ou null | `JSON` | La définition de notation à ce moment-là. |
| `latitude`, `longitude` | number ou null | `FLOAT64` | Le point d'où la question a été posée, pour les moniteurs localisés. |
| `ranAt` | timestamp | `TIMESTAMP` | UTC, précision à la microseconde. |

## Historique de livraison

Chaque fenêtre de chaque jeu de données est une exécution. Listez-les de la plus récente à la plus ancienne :

```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` | Signification |
| - | - |
| `pending` | En attente de livraison, ou d'une nouvelle tentative après un échec. `nextAttemptAt` indique quand. |
| `running` | En cours de livraison. |
| `delivered` | Écrite. `rows`, `bytes`, `files` et `deliveredAt` sont renseignés. |
| `failed` | Huit tentatives ont échoué. Plus rien ne se passe tant que vous ne la relancez pas. |

Filtrez avec `status`, `data` (`tasks` ou `monitor_results`) et `limit` (1–200, 50 par défaut) ;
renvoyez `nextCursor` comme `cursor` pour la page suivante.

* **Nouvelles tentatives automatiques.** Une tentative échouée est relancée après 15 minutes, puis le délai
  double jusqu'à 12 heures, huit tentatives en tout. `error` contient la raison donnée par le fournisseur de
  stockage : une autorisation manquante apparaît d'abord ici.
* **Renvoyer une fenêtre.** `POST /v1/exports/{id}/runs/{runId}/retry` envoie une fenêtre immédiatement :
  une fenêtre échouée après correction de l'accès, ou une fenêtre livrée que vous voulez réécrire. Il remet
  `attempts` à zéro et renvoie l'exécution en `pending`. Une exécution en cours de livraison renvoie
  `409 EXPORT_RUN_RUNNING`.
* **État de l'export.** `GET /v1/exports` et `GET /v1/exports/{id}` ajoutent `deliveredThrough`
  (la fin de la dernière fenêtre livrée), `failedRuns` et `retryingRuns` (exécutions en attente
  qui ont déjà échoué au moins une fois).

## Suspendre, reprendre et supprimer

* `PATCH /v1/exports/{id}` avec `{"enabled": false}` suspend un export. `{"enabled": true}`
  le reprend et rattrape les fenêtres manquées, jusqu'à 30 jours en arrière.
* `DELETE /v1/exports/{id}` arrête l'export. Les fichiers et partitions déjà livrés restent dans
  votre stockage.
* La destination, la fréquence et les jeux de données ne peuvent pas changer. Créez un nouvel export et supprimez
  l'ancien.

## Endpoints

| Méthode et chemin | Usage |
| - | - |
| [`GET /v1/exports/identity`](/fr/api-reference/exports/get-identity) | L'identité à autoriser et votre clé de compte |
| [`POST /v1/exports`](/fr/api-reference/exports/create-export) | Connecter une destination |
| [`GET /v1/exports`](/fr/api-reference/exports/list-exports) | Lister les exports avec leur état de livraison |
| [`GET /v1/exports/{id}`](/fr/api-reference/exports/get-export) | Un export |
| [`PATCH /v1/exports/{id}`](/fr/api-reference/exports/update-export) | Suspendre ou reprendre |
| [`DELETE /v1/exports/{id}`](/fr/api-reference/exports/delete-export) | Arrêter l'export |
| [`GET /v1/exports/{id}/runs`](/fr/api-reference/exports/list-runs) | Historique de livraison |
| [`POST /v1/exports/{id}/runs/{runId}/retry`](/fr/api-reference/exports/retry-run) | Renvoyer une fenêtre |

Un export qui ne vous appartient pas renvoie `404 NOT_FOUND`.


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