# Sube documentos desde tus propios sistemas
Source: https://nordvec.com/es/docs/guides/how-to/push-documents

Crea un origen de datos, sube documentos a él con una clave de API de indexación, elige quién puede leerlos y pausa o elimínalo cuando cambie el origen.



La API de push indexa documentos de sistemas para los que Nordvec no tiene conector: una exportación de wiki interna, un archivo de tickets, una base de datos de notas. Tú envías el texto y quién puede leerlo; Nordvec lo almacena en la UE, lo indexa y lo hace buscable y citable como cualquier otro documento. Cada documento enviado llega a un **origen de datos**, un contenedor con nombre en tu espacio de trabajo que un administrador del espacio crea primero. Un push que nombra un origen de datos que no existe, o que está pausado, se rechaza.

## Crea un origen de datos [#crea-un-origen-de-datos]

Abre **Configuración del espacio de trabajo > Orígenes de datos** y elige **Crear origen de datos**. Los administradores y propietarios del espacio de trabajo pueden hacerlo; en un espacio personal, eres tú.

| Campo  | Notas                                                                                                                                                |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nombre | Lo que ven las personas en la lista de configuración. Hasta 200 caracteres.                                                                          |
| Slug   | Lo que nombra cada push. Letras minúsculas, dígitos, `-` y `_`, empezando por una letra o dígito, hasta 200 caracteres. No se puede cambiar después. |

El slug `confluence-export` se usa en los ejemplos siguientes.

## Crea una clave de API de indexación [#crea-una-clave-de-api-de-indexación]

Los envíos se autentican con una clave API de la clase **Indexing** que lleva el ámbito `index:write`; añade `index:status` para hacer seguimiento de la ingesta y `index:delete` para eliminar documentos o reemplazar un origen de datos completo. Crea una bajo **Configuración del espacio de trabajo > Claves API**; la clave en bruto empieza por `nv_eu_idx_` y se muestra una sola vez. Consulta [Autenticación](/docs/guides/authentication). Cada solicitud también nombra tu id de espacio de trabajo como `tenantId`, el id en la dirección de tu espacio en la app (`/w/<workspace id>/...`), y debe ser el espacio al que pertenece la clave.

## Envía un documento [#envía-un-documento]

`/documents/push` crea el documento o lo actualiza si ya existe uno con el mismo `id` en el origen de datos.

```bash
curl https://nordvec.com/api/v1/documents/push \
  -H "Authorization: Bearer $NORDVEC_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: page-4711-2026-09-28" \
  -d '{
    "tenantId": "YOUR_WORKSPACE_ID",
    "document": {
      "id": "page-4711",
      "title": "Travel expense policy",
      "datasource": "confluence-export",
      "body": { "mimeType": "text/markdown", "content": "# Travel expenses\n..." },
      "permissions": {},
      "sourceUrl": "https://wiki.example.com/pages/4711",
      "type": "policy"
    }
  }'
```

```json
{ "documentId": "page-4711", "status": "queued", "updated": false }
```

* `id` es tu id estable para el documento dentro del origen de datos. Enviar el mismo `id` de nuevo lo actualiza; el contenido sin cambios se reconoce por su hash y no se indexa dos veces.
* `body.mimeType` es uno de `text/plain`, `text/markdown`, `text/html`, `application/pdf` o los tipos de Word, Excel y PowerPoint (`.docx`, `.xlsx`, `.pptx`). El contenido binario se envía codificado en base64.
* `sourceUrl` se convierte en el enlace "ir a la fuente" en cada cita del documento. Omítelo en un reenvío para mantener el almacenado, o envía `null` para borrarlo.
* `type` establece el `content_type` del documento, que la búsqueda y los filtros de lista utilizan.

Todo el cuerpo de la solicitud está limitado a 1 MB, por lo que un archivo grande o un lote grande responde con `413`; divídelo.

## Elige quién puede leerlo [#elige-quién-puede-leerlo]

`permissions` es obligatorio en cada push, por lo que nunca se toma una decisión de compartición al omitir un campo. En un origen de datos visible para el espacio de trabajo:

| `permissions`                             | Quién puede leer el documento                                                 |
| ----------------------------------------- | ----------------------------------------------------------------------------- |
| `{}`                                      | Todos los miembros del espacio de trabajo                                     |
| `{ "allowedUsers": ["ana@example.com"] }` | Solo las personas enumeradas                                                  |
| `{ "allowedGroups": ["GROUP_ID"] }`       | Miembros de esos grupos del espacio de trabajo, incluidos los grupos anidados |
| `{ "allowAllTenantMembers": false }`      | Rechazado: un documento que nadie puede leer es un borrado                    |

Para cambiar quién puede leer un documento sin enviar su contenido de nuevo, usa `POST /documents/push/permissions`. Hacer que un documento ya restringido sea visible para todo el espacio de trabajo además requiere el ámbito `index:acl-widen`, por lo que una sincronización rutinaria no puede deshacer silenciosamente una restricción que alguien estableció manualmente.

## Envía en lotes [#envía-en-lotes]

`/documents/push/bulk` acepta hasta 100 documentos para un origen de datos por llamada. La respuesta cuenta `accepted` y `rejected` y da un resultado por documento, por lo que un documento incorrecto no hace fallar el lote. El límite de 1 MB en el cuerpo se aplica por llamada, así que divide las subidas grandes en varias llamadas bajo el mismo `uploadId`.

```bash
curl https://nordvec.com/api/v1/documents/push/bulk \
  -H "Authorization: Bearer $NORDVEC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_WORKSPACE_ID",
    "uploadId": "nightly-2026-09-28",
    "datasource": "confluence-export",
    "documents": [
      { "id": "page-4711", "title": "Travel expense policy", "datasource": "confluence-export",
        "body": { "mimeType": "text/plain", "content": "..." }, "permissions": {} }
    ]
  }'
```

## Reemplazar un origen de datos completo [#reemplazar-un-origen-de-datos-completo]

Cuando tu sistema puede listar todo lo que debe contener un origen de datos, envía el listado completo como una **sesión de subida**, y los documentos que ya no contiene se mueven a la papelera cuando la sesión se cierra. Las sesiones necesitan una clave API de indexación que tenga `index:delete` además de `index:write`, porque el cierre elimina documentos; la clave que abre una es la única que puede continuarla.

1. Envía la primera página con `"isFirstPage": true`. Es la página `0`.
2. Envía cada página siguiente con su `pageIndex` (`1`, `2`, ...), en cualquier orden.
   Una página enviada dos veces se cuenta una sola vez, por lo que un reintento siempre es seguro.
3. Envía la última página con `"isLastPage": true` y su `pageIndex`. Un listado
   que quepa en una sola página envía `isFirstPage` y `isLastPage` juntos. La
   última página puede no llevar documentos.

Todas las páginas usan el mismo `uploadId`, y cada respuesta incluye el progreso de la sesión en `upload`. La sesión solo se cierra cuando ha llegado cada página desde `0` hasta la última. Cerrarla mueve a la papelera cada documento en el origen de datos que ninguna página de la sesión nombró y que existía antes de que la sesión se abriera. Cualquier otro push al origen de datos mientras la sesión está activa mantiene el documento que nombra: un único push, un lote sin campos de sesión, una actualización de permisos y un reenvío de contenido sin cambios por igual. La papelera guarda lo que el cierre movió allí durante 30 días; enviar un documento de nuevo lo recupera, y lo mismo ocurre al restaurar toda la sesión (ver más abajo).

Una sesión que no recibe ninguna página durante 24 horas caduca y se cierra sin eliminar nada. Una página rechazada se responde con `409 Conflict`, no escribe nada, y su `data.reason` indica el motivo:

| `reason`                                               | Qué hacer                                                                                                                                                                                                                                                                                                                                 |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `upload_incomplete`                                    | Envía las páginas listadas en `missingPageIndexes` y, después, la última página de nuevo                                                                                                                                                                                                                                                  |
| `deletion_confirmation_required`                       | El cierre movería a la papelera más del 20% del origen de datos. Si es correcto, envía la última página de nuevo con `"confirmDeletions"` establecido en `wouldTombstone`                                                                                                                                                                 |
| `deletion_confirmation_too_large`                      | `confirmDeletions` es mayor que el número de documentos que el origen de datos contenía cuando se abrió la sesión. Envía el recuento que esperas eliminar                                                                                                                                                                                 |
| `upload_in_progress`                                   | Hay una sesión abierta en este origen de datos. Si es de tu clave, termínala, espera a que expire o empieza de nuevo con `"forceRestartUpload": true` en tu primera página. Si la abrió otra clave, `forceRestartUpload` la reemplaza solo una vez que no haya recibido ninguna página durante una hora, desde la hora en `restartableAt` |
| `upload_expired`, `upload_missing`, `upload_restarted` | La sesión ha desaparecido; empieza una nueva con un nuevo `uploadId`                                                                                                                                                                                                                                                                      |
| `upload_closed`, `upload_id_reused`                    | El `uploadId` está agotado; usa uno nuevo                                                                                                                                                                                                                                                                                                 |
| `page_index_required`                                  | Tu clave tiene una sesión abierta en este origen de datos; envía `pageIndex` con la página                                                                                                                                                                                                                                                |

Para reanudar después de un fallo, lee la sesión con `GET /documents/push/upload?tenantId=...&datasource=...&uploadId=...` (ámbito `index:status`). Su `missingPageIndexes` lista las páginas que aún faltan por enviar.

### Deshacer el cierre de una sesión [#deshacer-el-cierre-de-una-sesión]

Si una sesión eliminó documentos que no debería haber eliminado, por ejemplo porque el listado que envió estaba incompleto, restáuralos en una sola llamada:

```bash
curl https://nordvec.com/api/v1/documents/push/upload/restore \
  -H "Authorization: Bearer $NORDVEC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tenantId": "YOUR_WORKSPACE_ID", "datasource": "confluence-export", "uploadId": "nightly-2026-09-28" }'
```

La clave que abrió la sesión puede restaurarla, y también puede hacerlo un administrador del espacio de trabajo que haya iniciado sesión en Nordvec, para una sesión abierta por cualquier clave. Todos los documentos que el cierre movió a la papelera vuelven con el contenido que tenían, y la respuesta cuenta cuántos: `restored` están activos de nuevo, `purged` ya habían sido eliminados definitivamente por la papelera, y `skipped` habían cambiado desde el cierre (se volvieron a enviar o se eliminaron de nuevo) y se dejaron como están. Restaurar una sesión dos veces responde con los mismos recuentos de la primera restauración y `"replayed": true`, y pone en cola cualquier documento restaurado que aún esté esperando a ser indexado, por lo que repetir una restauración que no respondió es seguro. Una sesión puede restaurarse hasta 35 días después de su cierre, y mientras la papelera aún conserve algún documento que eliminó. Una restauración rechazada se responde con `409 Conflict` y su `data.reason`:

| `reason`                 | Qué significa                                                                                                                                                                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `upload_not_closed`      | La sesión nunca se cerró, por lo que no eliminó nada                                                                                                                                                                                     |
| `upload_in_progress`     | Hay una sesión abierta en el origen de datos. Restaura una vez que se haya cerrado o expirado                                                                                                                                            |
| `restore_purged`         | Han pasado más de 30 días y la papelera ha eliminado todos los documentos. Vuelve a enviarlos                                                                                                                                            |
| `workspace_not_entitled` | El plan actual del espacio de trabajo no permite restaurar desde la papelera                                                                                                                                                             |
| `corpus_cap_exceeded`    | Restaurar los documentos superaría el límite de documentos del espacio de trabajo, por lo que ninguno se recuperó. `data.wouldRestore` es cuántos necesita y `data.headroom` cuántos caben. Libera espacio y, después, restaura de nuevo |

## Rastrea la ingesta [#rastrea-la-ingesta]

Un push responde tan pronto como el documento se pone en cola. Pregunta por su progreso con `GET /documents/push/status` (ámbito `index:status`), filtrado por origen de datos o id de documento. Un documento pasa de `queued` a `processing`, luego a `completed`, o a `failed` con un `error`.

## Cuando un push es rechazado [#cuando-un-push-es-rechazado]

Un push que nombra un origen de datos desconocido o pausado se responde con `422 Unprocessable Content`. El mensaje nombra el slug y enlaza a **Configuración del espacio de trabajo > Orígenes de datos** en tu espacio de trabajo, y el error `data` explica por qué y qué hacer:

```json
{
  "defined": true,
  "code": "UNPROCESSABLE_CONTENT",
  "status": 422,
  "message": "Datasource \"confluence-export\" is paused and accepts no documents. A workspace admin resumes it under Workspace settings > Datasources: https://nordvec.com/w/YOUR_WORKSPACE_ID/workspace/settings?tab=datasources",
  "data": {
    "why": "The datasource \"confluence-export\" is paused",
    "fix": "Resume it at https://nordvec.com/w/YOUR_WORKSPACE_ID/workspace/settings?tab=datasources, then retry the push",
    "link": "https://nordvec.com/docs/guides/how-to/push-documents"
  }
}
```

No reintentes estos automáticamente: solo tendrán éxito después de que un administrador cree o reanude el origen de datos.

## Elimina un documento [#elimina-un-documento]

`POST /documents/push/delete` (ámbito `index:delete`) elimina un documento enviado mediante su `datasource` y `id`. Los documentos que dejas de enviar no se eliminan por sí solos: borra cada uno que retires, o envía el listado completo del origen de datos como una sesión de subida, descrita anteriormente.

## Pausa, reanuda y elimina [#pausa-reanuda-y-elimina]

* **Pausar** rechaza cualquier push adicional en el origen de datos. Sus documentos siguen siendo buscables. Un push que ya se estaba escribiendo cuando lo pausas se completa.
* **Reanudar** acepta pushes de nuevo.
* **Eliminar** borra el origen de datos y todos los documentos enviados a él, junto con su índice de búsqueda. Tu propio sistema conserva su copia, por lo que volver a enviar después de recrear el origen de datos los restaura. Una eliminación no se puede deshacer.

Si otro administrador cambió el origen de datos después de que se cargara tu lista, la acción se rechaza y la lista se recarga, para que decidas de nuevo en función de lo que hay ahora. Cada creación, pausa, reanudación y eliminación queda registrada en el registro de auditoría del espacio de trabajo.

<Callout>
  La lista de configuración muestra a quién es visible cada origen de datos. Quién puede leer un documento enviado lo decide el `permissions` enviado con él; crear, pausar o eliminar un origen de datos nunca amplía el acceso a nada.
</Callout>

<Callout>
  Las escrituras de push son idempotentes: repite el mismo `Idempotency-Key` en cada reintento de una escritura, y un duplicado se responde desde el primer intento en lugar de aplicarse dos veces. Consulta [Errores y límites de tasa](/docs/guides/errors-and-rate-limits).
</Callout>

## Pasos siguientes [#pasos-siguientes]

<Cards>
  <Card title="Listar y recuperar documentos" href="/docs/guides/how-to/list-documents" />

  <Card title="Filtrar y refinar la búsqueda" href="/docs/guides/how-to/filter-search" />

  <Card title="Referencia de la API" href="/docs/api" />
</Cards>
