Ir al contenido
Sursa Developers

Sincronizar su sistema con una fuente personalizada

Una fuente personalizada conecta un sistema que no tiene un conector integrado: su wiki, su herramienta de tickets, una base de datos, una exportación de cualquier origen. Su código envía documentos a Sursa, y Sursa los convierte en tarjetas en la colección y las carpetas para las que está configurada la fuente, con la misma búsqueda, las mismas respuestas, la misma verificación y los mismos permisos que las tarjetas de cualquier otra fuente.

A diferencia de escribir tarjetas directamente, una fuente personalizada lleva la cuenta de lo que ha enviado. Al final de una sincronización completa, Sursa archiva todos los documentos que usted no envió, así que las eliminaciones en su sistema llegan a Sursa sin trabajo adicional.

Configurar la fuente

Un administrador crea la fuente en Sursa, en Sources → New source → Custom source (fuentes, fuente nueva, fuente personalizada), y elige:

  • la colección y, si lo desea, una carpeta para sus tarjetas;
  • el modo de carpetas: todas las tarjetas en la carpeta elegida, o subcarpetas que reproducen el path de cada documento;
  • los permisos: los permisos de la colección o «como en la fuente», en cuyo caso cada documento indica quién puede verlo.

La página de la fuente muestra su ID; los ejemplos usan 42.

Elegir una clave

ClaveEmpieza porPuede
Clave de la fuentekbsrc_Escribir documentos en esta fuente y nada más: no puede leer ni buscar. Créela en la página de la fuente, en API keys (claves de API de la fuente).
Clave de la organización con el ámbito import:writekb_Escribir en cualquier fuente personalizada de la organización y leer su estado. Para crear una fuente y sus claves hace falta el ámbito admin.

La clave de la fuente es la opción más segura para una sola integración, sobre todo si funciona en una plataforma de terceros. Una clave de la organización con import:write conviene a un servicio que alimenta varias fuentes.

Las dos claves se envían de la misma manera, y todos los endpoints de envío están en /v1/push/sources/{source_id}. Compruebe la clave y el estado de la fuente con GET /v1/push/sources/{source_id}:

curl https://api.sursa.com/v1/push/sources/42 \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY"
{"source_id": 42, "name": "Helpdesk articles", "documents": 1840, "open_sync": null}

El documento

CampoObligatorioDescripción
external_idsíSu ID estable del documento, de hasta 512 caracteres. Si vuelve a enviar el mismo ID, el documento se sustituye.
titlesíTítulo de la tarjeta, de hasta 500 caracteres. En un archivo, por defecto, el nombre del archivo.
contentsí, salvo que haya un archivoHasta 5 MB.
content_typenohtml (predeterminado), markdown o text. Del HTML se eliminan los scripts, los estilos, los formularios y los objetos incrustados.
urlnoEnlace al documento en su sistema, que se muestra en la tarjeta.
pathnoCarpetas, como un array (["Support", "Billing"]) o una cadena ("Support/Billing"), hasta 10 niveles.
permissionsno{"everyone": true} o {"emails": [...], "groups": [...]}. Se usa cuando los permisos de la fuente son «como en la fuente».
tagsnoHasta 50 etiquetas, que se añaden a las etiquetas de la fuente.
author_emailnoSi es un usuario de la organización, pasa a ser el responsable de la tarjeta.
updated_atnoCuándo cambió el documento en su sistema (RFC 3339).
metadatanoSus pares clave-valor en la tarjeta. Consulte Metadatos.
categorynoCategoría de la tarjeta: la clave de una categoría de la organización.
verifiers, verify_interval_daysnoQuién verifica la tarjeta (usuarios por correo electrónico y grupos) y con qué frecuencia, en días.
upload_idnoEl archivo del documento procedente de una subida por partes, en lugar de content.
attachmentsnoHasta 20 archivos más del documento, como una lista de upload_id. Cada uno se convierte en una tarjeta propia de la fuente.

En lugar de content, un único documento puede llevar un archivo de hasta 100 MB en una solicitud multipart/form-data: el archivo en la parte file y los campos anteriores como JSON en la parte document. Las subidas por partes para upload_id y attachments se crean con una clave de la organización que tenga el ámbito import:write y la finalidad import_attachment; una clave de fuente no puede crearlas.

Dos formas de enviar

Las actualizaciones directas convienen a los sistemas que le avisan de cada cambio, como un webhook de su herramienta de soporte o un paso en Zapier. Envíe un documento cuando se cree o cambie, y elimínelo cuando se retire:

SolicitudHace
POST /v1/push/sources/{source_id}/documentsCrea o sustituye un documento.
POST /v1/push/sources/{source_id}/documents/batchCrea o sustituye muchos documentos a la vez.
DELETE /v1/push/sources/{source_id}/documents/{external_id}Elimina un documento. Codifique el ID para URL.

Los cambios se convierten en tarjetas en aproximadamente un minuto; varios cambios seguidos se procesan juntos.

Las sincronizaciones convienen a las exportaciones periódicas: usted lo envía todo, o todo lo que ha cambiado, y Sursa concilia. El resto de esta guía trata de las sincronizaciones.

Ejecutar una sincronización completa

Una sincronización tiene tres pasos: abrir, enviar y cerrar.

1. Abrir

POST /v1/push/sources/{source_id}/syncs abre una sincronización y devuelve su número:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Idempotency-Key: sync-2026-10-24" \
  -H "Content-Type: application/json" \
  -d '{"type": "initial", "max_minutes": 180}'
{"sync_number": 7, "type": "initial", "status": "open", "opened_at": "2026-10-24T02:00:00Z",
 "expires_at": "2026-10-24T05:00:00Z", "pushed": 0, "removed": 0}
  • type es initial en la primera sincronización de la fuente e incremental una vez que se ha completado una sincronización. Una sincronización incremental antes de que se haya completado alguna devuelve sources.push_initial_required.
  • Solo puede haber una sincronización abierta a la vez: una segunda devuelve 409 sources.push_sync_open.
  • Una sincronización permanece abierta durante max_minutes (60 por defecto, hasta 1440). Después caduca: no se archiva nada y su número deja de aceptarse. Elija un tiempo holgadamente más largo de lo que tarda su exportación.

2. Enviar documentos

Envíe los documentos en lotes de hasta 500, con el número de la sincronización. El cuerpo de un lote ocupa hasta 50 MiB; los archivos dentro de un lote se pasan como upload_id.

curl -X POST https://api.sursa.com/v1/push/sources/42/documents/batch \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Idempotency-Key: sync-7-batch-1" \
  -H "Content-Type: application/json" \
  -d '{
    "sync_number": 7,
    "documents": [
      {"external_id": "faq-shipping", "title": "Shipping", "content_type": "markdown",
       "content": "# Shipping\n\nWe ship worldwide within 5 days.", "path": ["Support"]},
      {"external_id": "faq-refunds", "title": "Refunds", "content_type": "html",
       "content": "<p>Refunds take 14 days.</p>", "path": ["Support", "Billing"],
       "permissions": {"groups": ["Support"]}, "metadata": {"article_id": "1042"}}
    ]
  }'

La respuesta tiene un resultado para cada documento, en el orden en que los envió:

{
  "results": [
    {"external_id": "faq-shipping", "result": "unchanged", "status": "indexed", "card_id": "8c1d…", "version": "5e0f…"},
    {"external_id": "faq-refunds", "result": "updated", "status": "pending", "card_id": "3f2c…", "version": "a91b…"}
  ]
}
CampoSignificado
resultQué le ha pasado ahora al documento: created, updated, unchanged, deleted, not_found, error o skipped (en un lote atómico que no se aplicó).
statusEn qué punto está el documento en su camino hacia una tarjeta: pending, processing (la tarjeta está escrita y se está indexando), indexed, failed o removed.
card_idLa tarjeta del documento, una vez que existe.
versionUn hash del contenido y de los campos. El mismo documento enviado de nuevo tiene la misma versión y queda unchanged.
error, reasonPor qué falló el documento. reason es un código estable: content_invalid, file_rejected, too_large, limit_reached, index_failed o batch_rejected (falló otro documento de un lote atómico).

De forma predeterminada, cada documento de un lote se aplica por separado: un documento incorrecto no detiene a los demás.

Los documentos que no han cambiado desde la última sincronización no hace falta volver a enviarlos. Confírmelos por ID con POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch, hasta 1000 ID por solicitud, para que la conciliación completa los conserve:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/touch \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_ids": ["faq-contact", "faq-hours"]}'

3. Cerrar

POST /v1/push/sources/{source_id}/syncs/{sync_number}/close termina la sincronización:

curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/close \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "complete"}'
statusEfecto
completeConciliación completa. Se archivan todos los documentos de la fuente que no se enviaron ni se confirmaron en esta sincronización. Úselo solo cuando lo haya enviado todo.
complete_incrementalAplica lo que envió y no archiva nada.
failedNo archiva nada y conserva lo que ya se envió. Añada reason (por ejemplo, API_ERROR) y error_details para el registro.

Cierre con failed siempre que su exportación se detenga a medias: un complete después de una exportación parcial archivaría todos los documentos a los que no llegó. Repetir el mismo cierre devuelve el mismo resultado.

Después del cierre, Sursa convierte los documentos en tarjetas en aproximadamente un minuto. La página de la fuente muestra cada sincronización con el número de documentos enviados y archivados, y GET /v1/push/sources/{source_id}/syncs/{sync_number} devuelve los mismos contadores.

Sincronizaciones incrementales

Entre sincronizaciones completas, envíe solo lo que ha cambiado:

  1. Abra con "type": "incremental".
  2. Envíe los documentos cambiados y ponga en deletes los ID de los eliminados (más abajo).
  3. Cierre con complete_incremental.

Ejecute de vez en cuando una sincronización completa, por ejemplo cada semana, para recoger todo lo que se le haya escapado a una ejecución incremental.

Eliminar documentos en un lote

Un lote puede eliminar documentos a la vez que escribe otros. Enumere sus ID en deletes:

{
  "sync_number": 8,
  "documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
  "deletes": ["faq-old-returns", "faq-fax"]
}

Cada ID eliminado recibe su propia entrada en results, con result igual a deleted, o not_found si la fuente no tiene ese documento. Volver a eliminar el mismo ID no causa ningún problema.

Lotes atómicos

Algunos cambios solo tienen sentido juntos, por ejemplo un documento y el que lo sustituye. Envíe "atomic": true y el lote se aplicará por completo o no se aplicará: si algún documento no supera sus comprobaciones, no se aplica nada del lote, y la respuesta es 422 con el código sources.push_batch_rejected y el resultado de cada documento en error.details.results: los documentos que fallaron tienen error, y los demás, skipped.

{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}

Sin atomic, un lote se aplica documento por documento. Use lotes atómicos para cambios relacionados, y lotes normales para cargas masivas, en las que un documento incorrecto no debe frenar al resto.

Comprobar el resultado de cada documento

La respuesta del lote le indica cómo se escribió cada documento. La conversión en tarjeta ocurre después, así que status todavía puede ser pending. Para encontrar los documentos de una sincronización que no se convirtieron en tarjetas:

curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
  -H "Authorization: Bearer $SURSA_SOURCE_KEY"

Cada entrada tiene external_id, title, status, card_id, version y reason, y la lista se pagina con cursor. status también acepta pending, processing, indexed y removed.

También puede recibir el aviso en lugar de preguntar: los eventos import.sync_completed (una sincronización se ha cerrado y procesado, con sus totales) e import.document_failed (un documento no se convirtió en tarjeta, con su reason) llegan por webhook y al feed de eventos.

Reintentos

  • Envíe una Idempotency-Key con cada POST. Un lote repetido con la misma clave devuelve el primer resultado.
  • Incluso sin la clave, un documento con el mismo external_id nunca se convierte en una segunda tarjeta: queda unchanged o updated.
  • Si el proceso se detiene en mitad de una sincronización, abra una nueva cuando caduque la anterior, o cierre la anterior con failed si todavía tiene su número, y vuelva a ejecutar la sincronización.

Límites

LímiteValor
Contenido de un documento5 MB
Archivo en una solicitud de un solo documento100 MB
Documentos por lote500
Cuerpo de la solicitud de un lote50 MiB
ID por solicitud touch1000
Documentos por fuenteDepende del plan: desde 100.000
Sincronización abierta60 minutos por defecto, hasta 24 horas

Un documento que supera el límite de documentos de la fuente falla con el motivo limit_reached en un lote; una solicitud de un solo documento responde 409 con el código sources.push_too_many_documents. Los límites de frecuencia se aplican como a cualquier otra solicitud; consulte Límites de frecuencia y cuotas.

Errores frecuentes

RespuestaCausaQué hacer
401 sources.push_key_invalidLa clave es incorrecta, se ha revocado o pertenece a otra fuente.Compruebe la clave y el ID de la fuente en la ruta.
400 sources.push_document_invalidFalta un campo obligatorio o se ha superado un límite.Corrija el documento; en un lote normal, solo falla ese documento.
409 sources.push_sync_openHay otra sincronización abierta.Ciérrela o espere a que caduque.
409 sources.push_sync_closedLa sincronización está cerrada o ha caducado.Abra una sincronización nueva; aumente max_minutes para las exportaciones largas.
403 sources.feature_disabledLas fuentes no forman parte del plan de la organización.Póngase en contacto con el administrador.
429Demasiadas solicitudes.Espere lo que indica Retry-After; envíe menos lotes y más grandes.