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

# Exportación de resultados a Amazon S3, Google Cloud Storage y BigQuery

> Recibe cada tarea terminada y cada respuesta puntuada de los monitores como archivos JSON Lines por hora o por día en tu propio bucket, o como particiones de una tabla de BigQuery.

Cada hora o cada día UTC, una exportación escribe los resultados de la ventana como JSON Lines comprimido con
gzip en un bucket de Amazon S3 o Google Cloud Storage, o los carga en una partición de una tabla de BigQuery. Tu
data warehouse los lee como cualquier otra fuente, sin bucle de sondeo.

Concedes a nuestra identidad de exportación permiso de escritura en el bucket o el dataset; nunca compartes claves
ni contraseñas. Todas las claves, buckets, IDs de cuenta y roles de esta página son ejemplos.

## Qué se exporta

| Conjunto de datos | Filas | Ventana según | Mismos campos que |
| - | - | - | - |
| `tasks` | Cada tarea de la cuenta que terminó como `COMPLETED` o `FAILED` | `completedAt` | [`GET /v1/async/task/{id}`](/es/api-reference/get-task) y el webhook |
| `monitor_results` | Cada respuesta puntuada de cada monitor de la cuenta | `ranAt` | [`GET /v1/monitors/{id}/results?includeEvidence=true`](/es/api-reference/monitors/export-results) |

Se incluyen las tareas enviadas con cualquier clave de la cuenta, desde el Playground y por los monitores. Una
ventana contiene exactamente las filas cuyo tiempo cae en `[windowStart, windowEnd)`.

**Momento de la entrega.** Una ventana vence 10 minutos después de cerrarse, para que incluya los cobros
liquidados en el límite. Un proceso que se ejecuta cada 15 minutos recoge las ventanas vencidas, así que la
entrega suele empezar entre 10 y 25 minutos después de que se cierre la ventana.

## Configurar una exportación

**1. Consulta tu identidad de exportación**

```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` da nombre a tu carpeta y a tus tablas. Todas las rutas y tablas que escribimos
lo llevan, así que varias cuentas de querying.ai pueden compartir un bucket o dataset y cada una
escribe solo sus propios archivos. Concede permiso a la identidad que muestra tu respuesta, no al ejemplo de arriba.

**2. Concede acceso**

Concede a la identidad acceso a tu destino. Consulta
[Conceder acceso](#conceder-acceso) para S3, Cloud Storage y BigQuery.

**3. Crea la exportación**

`POST /v1/exports` comprueba el permiso y guarda la exportación. Consulta
[Crear la exportación](#crear-la-exportación).

**4. Sigue la primera entrega**

`GET /v1/exports/{id}/runs` lista cada ventana y su estado. Consulta
[Historial de entregas](#historial-de-entregas).

## Conceder acceso

### Amazon S3

Crea en tu cuenta de AWS un rol de IAM que nuestra identidad de Google pueda asumir. Usa el
`trustPolicy` de la respuesta de identidad como política de confianza del rol. Acepta solo nuestra
identidad de exportación y solo con el nombre de sesión de tu cuenta:

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

Adjunta una política de permisos que deje al rol escribir bajo tu prefijo:

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

Si el bucket cifra con una clave KMS administrada por el cliente, permite también `kms:GenerateDataKey` sobre
esa clave.

### Google Cloud Storage

Concede a la cuenta de servicio de exportación **Storage Object User** (`roles/storage.objectUser`) en
el bucket. Crea los archivos y los reemplaza cuando una ventana se vuelve a enviar.

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

Para limitar el permiso a tu carpeta, añade una condición de IAM sobre
`resource.name.startsWith("projects/_/buckets/acme-geo/objects/querying/acct_3f9a1c2b7d4e/")`.

### BigQuery

Concede a la cuenta de servicio de exportación **BigQuery Data Editor** (`roles/bigquery.dataEditor`) en
el dataset. Ejecutamos los trabajos de carga en nuestro propio proyecto, así que cargar no te cuesta nada;
solo pagas el almacenamiento y las consultas que ejecutes.

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

## Crear la exportación

Usa una clave de API sin restricción de motores: una exportación lleva todos los resultados de la cuenta, así
que una clave limitada a algunos motores recibe `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"
  }'
```

| Campo | Obligatorio | Descripción |
| - | - | - |
| `destination.type` | Sí | `s3`, `gcs` o `bigquery`. |
| `destination.bucket` | S3, GCS | El nombre del bucket. |
| `destination.prefix` | No | Carpeta dentro del bucket, hasta 256 caracteres, relativa (sin `/` inicial ni segmentos `.` o `..`). Se añade una `/` final. |
| `destination.region` | S3 | La región de AWS del bucket, como `us-east-1`. |
| `destination.roleArn` | S3 | El rol de [Conceder acceso](#amazon-s3), `arn:aws:iam::<account>:role/<name>`. |
| `destination.projectId`, `destination.datasetId` | BigQuery | El proyecto y el dataset de Google Cloud. |
| `interval` | No | `hourly` o `daily` (predeterminado). Se mantiene durante toda la vida de la exportación. |
| `data` | No | `tasks`, `monitor_results` o ambos (predeterminado). |
| `startAt` | No | Hora ISO 8601, no futura y de hasta 30 días atrás. La primera ventana es la que la contiene. Por defecto: ahora. |

Antes de guardarla, la exportación comprueba el permiso. En S3 y Cloud Storage escribe
`<prefix><accountKey>/_querying/connection-check.json`; en BigQuery lee el dataset
y registra su ubicación. Si la comprobación falla, no se guarda nada. Una cuenta puede tener hasta 10
exportaciones.

La respuesta es `201` con la exportación:

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

En S3 y Cloud Storage, `destination` repite la configuración del bucket y añade `path`, la
carpeta donde llegan tus archivos, como `s3://acme-geo/querying/acct_3f9a1c2b7d4e/` o
`gs://acme-geo/querying/acct_3f9a1c2b7d4e/`. `nextWindowStart` es el inicio de la siguiente
ventana que se planificará.

### Errores

| Estado | Código | Causa |
| - | - | - |
| `400` | `VALIDATION_ERROR` | JSON no válido o un campo fuera de rango. El mensaje nombra el campo, como `destination.region: region is the bucket's AWS region, e.g. us-east-1`. |
| `403` | `KEY_SCOPE` | La clave de API está limitada a algunos motores. |
| `409` | `EXPORT_LIMIT` | La cuenta ya tiene 10 exportaciones. |
| `422` | `EXPORT_DESTINATION_UNREACHABLE` | La comprobación de conexión falló. El mensaje incluye el motivo del proveedor de almacenamiento, normalmente un permiso que falta. |
| `502` | `EXPORT_CHECK_FAILED` | No se pudo alcanzar el destino. Vuelve a intentarlo. |
| `503` | `EXPORTS_NOT_CONFIGURED` | Las exportaciones a este tipo de destino no están disponibles. |

## Archivos y tablas

### Archivos en S3 y 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
```

* Los directorios siguen la partición de Hive (`dt=`, y `hour=` en exportaciones por hora), así que Athena,
  las tablas externas de BigQuery y Spark los leen como columnas.
* `v1` es la versión del esquema (`schemaVersion` en la exportación). Un cambio que rompa una columna
  se publica como `v2` a su lado.
* Una ventana se divide en partes de hasta 100.000 filas, en orden temporal.
* `_manifest.json` se escribe al final. Carga una ventana cuando exista su manifiesto y toma de él la
  lista de partes:

```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` del manifiesto coincide con el número de líneas de sus partes y con el `rows` de la ejecución en
el historial de entregas. Los nombres de archivo dependen solo de la ventana, así que una ventana reenviada
reemplaza los mismos objetos.

### Tablas de BigQuery

Las exportaciones a BigQuery cargan en `querying_tasks_v1_<accountKey>` y
`querying_monitor_results_v1_<accountKey>`, creadas en la primera carga y particionadas por
`completedAt` o `ranAt` (por día, o por hora en exportaciones por hora). Cada ventana reemplaza su
propia partición, así que una ventana reenviada nunca se duplica. `payload`, `response`, `sources` y
`scoringContext` son columnas `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";
```

## Esquema de filas (v1)

### `tasks`

| Campo | Tipo | Tipo en BigQuery | Descripción |
| - | - | - | - |
| `id` | string | `STRING` | ID de la tarea. |
| `taskType` | string | `STRING` | Motor, como `CHATGPT`. |
| `status` | string | `STRING` | `COMPLETED` o `FAILED`. |
| `priority` | integer | `INT64` | Tal como se envió. |
| `idempotencyKey` | string o null | `STRING` | Tu clave, si enviaste una. |
| `createdAt`, `completedAt` | timestamp | `TIMESTAMP` | UTC, precisión de microsegundos. |
| `monitorId` | string o null | `STRING` | El monitor que la ejecutó. |
| `creditsCharged` | decimal | `NUMERIC` | Créditos cobrados por la tarea, con hasta dos decimales (por ejemplo `1.25`). `0` en una tarea fallida. Léelo como decimal, no como entero. |
| `payload` | object | `JSON` | El payload tal como se envió. |
| `response` | object o null | `JSON` | El resultado tal como lo devuelve `GET /v1/async/task/{id}`; `null` si la tarea falló. |
| `error` | string o null | `STRING` | El motivo del fallo, empezando por su código; `null` si se completó. |

### `monitor_results`

| Campo | Tipo | Tipo en BigQuery | Descripción |
| - | - | - | - |
| `id`, `monitorId`, `taskId` | string | `STRING` | IDs del resultado, del monitor y de la tarea. |
| `engine`, `prompt` | string | `STRING` | Qué se preguntó y dónde. |
| `mentioned`, `cited` | boolean | `BOOL` | Marca nombrada; tu dominio citado. |
| `position` | integer o null | `INT64` | Posición en caracteres de la primera mención de la marca. |
| `competitorHits` | string array | `STRING`, repetido | Competidores nombrados en la respuesta. |
| `sources` | array | `JSON` | Citas como `{url, label, position}`. |
| `answerText` | string o null | `STRING` | La respuesta de la que se leyó la puntuación. |
| `scoringContext` | object o null | `JSON` | La definición de puntuación en ese momento. |
| `latitude`, `longitude` | number o null | `FLOAT64` | El punto desde el que se preguntó, en monitores de ubicación. |
| `ranAt` | timestamp | `TIMESTAMP` | UTC, precisión de microsegundos. |

## Historial de entregas

Cada ventana de cada conjunto de datos es una ejecución. Lístalas de la más reciente a la más antigua:

```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` | Significado |
| - | - |
| `pending` | Esperando a entregarse, o esperando a reintentarse tras un intento fallido. `nextAttemptAt` indica cuándo. |
| `running` | Se está entregando ahora. |
| `delivered` | Escrita. `rows`, `bytes`, `files` y `deliveredAt` tienen valor. |
| `failed` | Fallaron ocho intentos. No pasa nada más hasta que la reintentes. |

Filtra con `status`, `data` (`tasks` o `monitor_results`) y `limit` (1–200, por defecto
50\); devuelve `nextCursor` como `cursor` para obtener la página siguiente.

* **Reintentos automáticos.** Un intento fallido se reintenta a los 15 minutos y después con un intervalo
  que se duplica hasta 12 horas, ocho intentos en total. `error` contiene el motivo del proveedor de
  almacenamiento, así que un permiso que falta aparece aquí primero.
* **Volver a enviar una ventana.** `POST /v1/exports/{id}/runs/{runId}/retry` envía una ventana ahora: una
  fallida después de corregir el permiso, o una entregada que quieres reescribir. Reinicia
  `attempts` y devuelve la ejecución como `pending`. Una ejecución que se está entregando devuelve
  `409 EXPORT_RUN_RUNNING`.
* **Estado de la exportación.** `GET /v1/exports` y `GET /v1/exports/{id}` añaden `deliveredThrough`
  (el final de la última ventana entregada), `failedRuns` y `retryingRuns` (ejecuciones pendientes
  que ya fallaron al menos una vez).

## Pausar, reanudar y eliminar

* `PATCH /v1/exports/{id}` con `{"enabled": false}` pausa una exportación. `{"enabled": true}`
  la reanuda y recupera las ventanas que se perdió, hasta 30 días atrás.
* `DELETE /v1/exports/{id}` detiene la exportación. Los archivos y particiones ya entregados se quedan en
  tu almacenamiento.
* El destino, la frecuencia y los conjuntos de datos no se pueden cambiar. Crea una exportación nueva y
  elimina la anterior.

## Endpoints

| Método y ruta | Uso |
| - | - |
| [`GET /v1/exports/identity`](/es/api-reference/exports/get-identity) | La identidad a la que dar permiso y tu clave de cuenta |
| [`POST /v1/exports`](/es/api-reference/exports/create-export) | Conectar un destino |
| [`GET /v1/exports`](/es/api-reference/exports/list-exports) | Listar exportaciones con su estado de entrega |
| [`GET /v1/exports/{id}`](/es/api-reference/exports/get-export) | Una exportación |
| [`PATCH /v1/exports/{id}`](/es/api-reference/exports/update-export) | Pausar o reanudar |
| [`DELETE /v1/exports/{id}`](/es/api-reference/exports/delete-export) | Detener la exportación |
| [`GET /v1/exports/{id}/runs`](/es/api-reference/exports/list-runs) | Historial de entregas |
| [`POST /v1/exports/{id}/runs/{runId}/retry`](/es/api-reference/exports/retry-run) | Volver a enviar una ventana |

Una exportación que no te pertenece devuelve `404 NOT_FOUND`.


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