Documentación para subir, listar y descargar archivos de Consultora Portas
v1 · REST · JSON · Bearer auth
ⓘ Este valor se usa en todos los ejemplos. Edítelo y los códigos de abajo se actualizan automáticamente.
El path /portas/api es el prefijo fijo del API; podría cambiar el dominio en el futuro.
Subir archivos PDF/JPG de una carpeta operativa del despachante.
Obtener los entregables consolidados de esa carpeta — paquetes PDF unidos y ZIPs
generados automáticamente a partir de los archivos subidos — más los archivos individuales por separado.
Cada entregable y cada archivo individual queda registrado con un token público de descarga.
Ese token permite armar URLs clickeables que se pueden publicar tal cual en el sitio del proveedor para que
los clientes finales descarguen los documentos.
Flujo recomendado: el proveedor consulta GET /v1/operaciones/{id_carpeta}/paquetes
con su API key → la respuesta trae entregables (PDFs unidos, ZIPs) y archivos
(individuales) → cada uno con su download_url → esas URLs se publican en su sitio.
2. Autenticación
Toda llamada al API (excepto el healthcheck y las URLs públicas de descarga por token) requiere el header
Authorization: Bearer <api-key>.
La API key se entrega de forma privada al proveedor por canal seguro. Nunca se publica
en código frontend ni en URLs visibles. Trátela como una contraseña.
Scopes: cada API key tiene un conjunto de permisos (read, upload, delete).
Si su key no incluye un scope necesario, el endpoint responde 403 forbidden_scope.
3. Convenciones
Las respuestas son siempre JSON, salvo las descargas binarias (PDF, ZIP, JPG).
Las respuestas exitosas tienen "ok": true; las de error "ok": false + error + message.
Las fechas se devuelven en formato ISO-8601 (YYYY-MM-DD HH:MM:SS, zona Argentina).
Los tamaños de archivo están en bytes.
Encoding UTF-8.
El método POST con archivos usa multipart/form-data. El resto, application/json o querystring.
4. Glosario
Término
Significado
Ejemplo
id_carpeta
Identificador completo de una carpeta operativa, formato anio.id_despachante.nro_interno.
2026.04.98765
anio
Año (4 dígitos) de la carpeta.
2026
id_despachante
ID interno del despachante (2 chars).
04
nro_interno
Número de carpeta interno del despachante.
98765
sub_carpeta
Carpeta lógica donde se clasifica el archivo. Ver lista de valores válidos en sección 6.
Gastos, Factura_Portas
familia
Grupo de sub_carpetas que se consolida en un entregable.
gastos, f3101, factura_portas
entregable
Archivo final generado por el server (PDF unido o ZIP) a partir de los archivos de una familia.
"Gastos REF 2026_04_98765.pdf"
id_archivo
ID interno secuencial del archivo individual en la base.
34511
download_token
Token público de 64 hex que permite descargar sin auth.
4f2e2ae78613…
hash_sha1
Hash SHA1 del contenido del archivo (40 hex, minúsculas).
3a52ce780950d4d969792a2559cd519d7ee8c727
idempotency_key
Clave opcional (≤80 chars, alfanumérica + _-) que evita duplicación en reintentos de subida.
upload_2026_04_98765_001
5.1 Healthcheck
GET/v1 — sin auth
Devuelve estado del servicio. Útil para verificar conectividad.
Devuelve los entregables consolidados de la carpeta (PDFs unidos, ZIPs) y los
archivos individuales. Cada uno con un download_url público clickeable.
Este es el endpoint que el proveedor consume para armar la página del cliente final.
const base = 'https://api.portascloud.ar';
const apiKey = 'TU_API_KEY';
const ic = '2026.04.98765';
const r = await fetch(`${base}/v1/operaciones/${ic}/paquetes`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
const data = await r.json();
for (const e of data.entregables) {
if (e.estado === 'ready') {
document.body.insertAdjacentHTML('beforeend',
`<a href="${e.download_url}">${e.nombre}</a><br>`);
}
}
import requests
base = 'https://api.portascloud.ar'
api_key = 'TU_API_KEY'
ic = '2026.04.98765'
r = requests.get(f'{base}/v1/operaciones/{ic}/paquetes',
headers={'Authorization': f'Bearer {api_key}'})
data = r.json()
for e in data['entregables']:
if e['estado'] == 'ready':
print(e['nombre'], '->', e['download_url'])
Encolado para procesar. Esperando debounce (30s sin uploads en la familia) y siguiente tick del worker (cada 1 min).
processing
Generándose ahora mismo.
ready
Listo. download_url disponible.
failed
Falló (ver campo error). El worker reintenta automáticamente hasta 5 veces.
Si llama al endpoint y los entregables están en pending, espere 30-90 segundos y vuelva a consultar.
5.3 Descarga pública de un entregable (SIN AUTH)
GET/v1/de/{download_token} — público
Devuelve el binario del entregable (PDF unido o ZIP) directamente, con headers de descarga.
Esta es la URL que aparece en download_url dentro de cada entregable en el endpoint anterior.
Seguridad: el token son 64 caracteres hex aleatorios.
No revela el nombre del archivo ni permite inferir otros tokens. Es permanente (no expira).
Si se filtra, solo afecta a ese entregable; el resto del catálogo queda protegido.
Ejemplo
# Click directo desde browser, <a href>, curl, etc:https://api.portascloud.ar/v1/de/6998cc4a120afc8f3306b10d44b7184d3b37c6ab68b25261116361b7a6fc7230
5.4 Descarga pública de un archivo individual (SIN AUTH)
GET/v1/d/{download_token} — público
Igual que la anterior pero para los archivos individuales (los Scan, PDFs sueltos). URL aparece en
download_url dentro de archivos[].
Note la diferencia de path: /v1/de/ (con "e") para entregables, /v1/d/ para archivos individuales.
5.5 Listar archivos individuales
GET/v1/archivos — scope: read
Alternativa al endpoint principal cuando solo se necesita la lista cruda de archivos individuales con filtros
(por año, cliente, hash, etc.) sin los entregables.
Parámetros de query
Parámetro
Tipo
Requisito
Descripción
id_carpeta
string
opcional
Filtrar por carpeta (2026.04.98765).
anio
int
opcional
Filtrar por año.
id_cliente
int / lista
opcional
Filtrar por cliente final. Acepta uno o varios separados por coma (84,1167), para quien gestiona más de una empresa. Si viene pero no tiene ningún entero válido → 400 id_cliente_invalido.
const r = await fetch('https://api.portascloud.ar/v1/archivos?id_carpeta=2026.04.98765',
{ headers: { 'Authorization': 'Bearer TU_API_KEY' } });
const data = await r.json();
for (const f of data.rows) console.log(f.nombre_archivo, f.download_url);
import requests
r = requests.get('https://api.portascloud.ar/v1/archivos',
params={'id_carpeta': '2026.04.98765'},
headers={'Authorization': 'Bearer TU_API_KEY'})
for f in r.json()['rows']: print(f['nombre_archivo'], f['download_url'])
Después de subir: si el archivo va a una sub_carpeta que forma parte de una familia
(ver sección 6), el server marca el entregable correspondiente como pending.
El worker espera 30s de quietud y luego lo regenera. Vas a verlo en estado ready dentro de ~1-2 minutos.
5.9 Baja de archivo
DELETE/v1/archivos/{id} — scope: delete
Baja lógica (estado='BAJA'). El archivo queda en disco pero deja de aparecer en listados y descargas devuelven 404.
6. Subcarpetas válidas
El campo sub_carpeta al subir un archivo determina en qué carpeta lógica se guarda y a qué familia de
entregable contribuye. Los nombres se normalizan (case-insensitive, acentos opcionales).
Subcarpetas que contribuyen a un entregable
sub_carpeta canónica
Aliases aceptados
Familia de entregable
Tipos generados
Gastos
—
gastos
PDF + ZIP
Factura_Portas
Factura Portas
factura_portas
PDF unido
OM_Declaracion
OM Declaracion y sobre contenedor, 1
f3101 (1ra parte)
PDF unido
Factura_Comercial
Factura comercial formulario de valor, 2
f3101 (2da parte)
PDF unido
Conocimiento_Embarque
Conocimiento de embarque, 3
f3101 (3ra parte)
PDF unido
Cert_Origen
Certificado de origen, 4
f3101 (4ta parte)
PDF unido
Terceros_Organismos
3ros organismos y demas documentos, 5
f3101 (5ta parte)
PDF unido
DJAI
—
djai
PDF unido
Certificados_Importacion
Certificado de importacion
cert_importacion
PDF unido
PDF_Provisorio
PDF provisorio
pdf_provisorio
PDF (passthrough / unido si hay varios)
Otras subcarpetas usuales (sin entregable)
Estas sub_carpetas se guardan en la carpeta pero no contribuyen a ningún entregable consolidado:
F3101 — formularios F3101 ya unidos por el cliente VB.NET
Eventos/{tipo}/{id} — adjuntos a eventos del trámite
Si subís un archivo con una sub_carpeta que no está en la primera tabla, se guarda sin problemas
pero no dispara la regeneración de un entregable. Aparece solo en la lista archivos del endpoint principal.
Caso de uso típico del proveedor: en su web, dado un id_carpeta, mostrar los entregables consolidados
(links principales) y opcionalmente la lista completa de archivos individuales (vista detallada).
import requests
base = 'https://api.portascloud.ar'
api_key = 'TU_API_KEY'
ic = '2026.04.98765'
r = requests.get(f'{base}/v1/operaciones/{ic}/paquetes',
headers={'Authorization': f'Bearer {api_key}'})
data = r.json()
print('=== Entregables ===')
for e in data['entregables']:
if e['estado'] == 'ready':
print(f"{e['nombre']:50} {e['download_url']}")
else:
print(f" ({e['familia']}.{e['tipo']} en {e['estado']})")
print(f"\n=== Archivos individuales ({len(data['archivos'])}) ===")
for a in data['archivos']:
print(f"[{a['sub_carpeta']:20}] {a['nombre']:40} {a['download_url']}")
Pro tip: el endpoint /v1/operaciones/{id_carpeta}/paquetes es idempotente y rápido (~50ms).
Se lo puede llamar en cada pageview del cliente — no es necesario cachear. Si se desea cachear, hágalo con TTL corto (1-2 min)
para que los entregables nuevos aparezcan rápido cuando pasan de pending a ready.