Lee Envíos con un token de API de gestión con alcance
Un token de la API de gestión se guarda como hash, se muestra una vez y se limita por Habilidad: cinco rutas de lectura sobre formularios, Envíos, rechazos y un hilo de intento, con paginación por cursor y sin ninguna escritura.
Esta publicación se tradujo automáticamente. Lee el original en inglés

La API de gestión es el lado de lectura de FormFlow: cinco rutas GET, un token de portador y ninguna forma de escribir nada. Es la superficie que las herramientas del equipo usan cuando necesitan los Envíos que FormFlow ya guarda, no una copia en una hoja de cálculo.
Haz el token tan estrecho como el trabajo
Un token pertenece al equipo, no a una persona. Al crearlo le das un nombre, al menos una Habilidad — submissions:read, refusals:read o forms:read —, opcionalmente una lista de formularios y, opcionalmente, una fecha de caducidad. FormFlow solo guarda un hash, así que la credencial se muestra una vez, al crearla, y nunca más. Revocarlo es inmediato; un token caducado conserva su fila y libera su plaza.
Dos de esos ajustes hacen casi todo el trabajo. Un token limitado a formularios nombrados llega a esos formularios y a nada más. Un token con solo forms:read puede listar metadatos de formularios sin leer un solo Envío. Ninguno es una preferencia: una lectura fuera del alcance del token responde exactamente como la lectura de un registro que no existe, así que un registro ausente y uno prohibido se ven igual.
Las cinco lecturas
Todas las rutas están bajo /api/v1/manage y se autentican con un token de portador en la cabecera Authorization.
GET /api/v1/manage/forms — metadatos de formularios. Requiere forms:read.
GET /api/v1/manage/submissions — una página de Envíos. Requiere submissions:read.
GET /api/v1/manage/submissions/{uuid} — un Envío, incluidas las señales de spam que la lista omite.
GET /api/v1/manage/refused-submissions — los rechazos que guardó el registro del formulario. Requiere refusals:read.
GET /api/v1/manage/attempts/{attemptId} — la vida ordenada de un intento a través de los registros que la anotaron.
El cuerpo de un Envío va indexado por nombre de campo y se devuelve tal como se envió. Casi todos los campos son cadenas, un multiselección es una lista, un campo de archivo es una referencia con su nombre almacenado y una cuadrícula es un objeto indexado por la etiqueta de fila. La ruta de un solo Envío es la única que devuelve señales de spam.
Pagina con el cursor
Las rutas de lista responden con data y meta. limit acepta de 1 a 200 y por defecto 50, y el orden es created_at y luego id, descendente. meta.has_more dice si existe otra página; meta.next_cursor es el valor opaco que devuelves como cursor. No hay desplazamiento, porque el conjunto se mueve mientras lees y un desplazamiento saltaría o repetiría filas en silencio.
cursor=""
while :; do
page=$(curl -sS "https://formflow.digital/api/v1/manage/submissions?limit=100&cursor=$cursor" \
-H "Authorization: Bearer $FORMFLOW_TOKEN")
echo "$page" | jq -r '.data[] | [.uuid, .form_id, .created_at] | @tsv'
cursor=$(echo "$page" | jq -r '.meta.next_cursor // empty')
[ "$(echo "$page" | jq -r '.meta.has_more')" = "true" ] || break
doneLos filtros son estrechos a propósito: form_id, since, until, is_spam, unread y q. q es búsqueda por token exacto sobre un índice ciego, no búsqueda de subcadenas, y solo responde donde la indexación de búsqueda está activada.
Sigue un rechazo hasta su intento
Un Envío rechazado y un Envío son registros distintos. El rechazo se guarda para que el cliente pueda actuar sobre él, nunca se entrega y nunca se convierte en un Envío contado. Ambos llevan un identificador de intento, y la ruta de intentos reúne el hilo de ese intento — fricción de Preflight, rechazo, aceptación, rescate, recuperación, recibo y cada obligación de entrega — sin valores enviados ni metadatos del remitente.
Un identificador de intento no es único por sí solo, así que el hilo siempre se limita a un formulario. Cuando el identificador existe en más de uno, la respuesta es 409 y los nombra, y repites la petición con form_uuid para elegir.
Dónde la superficie de lectura es contundente
Otros tres límites conviene conocerlos antes de construir encima. Los cuerpos se descifran dentro de FormFlow y se devuelven tal como se almacenaron, así que un token que lee Envíos es un token que lee datos personales, y su almacenamiento merece el mismo cuidado que la credencial. Una fila cuyo cuerpo no se puede descifrar vuelve con payload_error igual a payload_unavailable mientras el resto de la página llega igual. Y los códigos son precisos: 401 para un token inválido, caducado o revocado; 403 por una Habilidad ausente o un plan no disponible; 404 cuando el registro está fuera del alcance del token; 422 por un filtro o cursor inválido; y 429 con Retry-After por el límite de tasa.
El contrato completo — cada parámetro, forma de respuesta y error — está en /docs/api. Y la entrada del Registro de cambios de v1.0.0 registra la API tal como salió: una API de gestión documentada junto al único endpoint que recibe Envíos.