Skip to main content
Toda la API está en {BASE_URL}/studio/... (privada, requiere STUDIO_KEY) o {BASE_URL}/public/artefacto/{id}/... (pública, requiere api_key del artefacto).

Convenciones

ConceptoValor
BASE_URLhttps://puente-backend-721178029791.southamerica-west1.run.app/
Auth privadaX-API-Key: puente_studio_xxxxxxxxxxxx
Auth públicaX-API-Key: puente_artifact_xxxxxxxxxxxx
Content-Typeapplication/json en POST/PUT

Endpoints privados — Artefactos

Requieren X-API-Key: {STUDIO_KEY}.

Listar artefactos

GET {BASE_URL}/studio/artefactos
Retorna los artefactos del equipo asociado a tu STUDIO_KEY.

Obtener un artefacto

GET {BASE_URL}/studio/artefactos/{id}
Retorna el código fuente completo en formato JSON (o HTML si es legacy).

Crear artefacto

POST {BASE_URL}/studio/artefactos
Content-Type: application/json

{
  "titulo": "Nombre de la app",
  "descripcion": "Descripción opcional",
  "equipo_id": null,
  "app_content": {
    "index.tsx": { "content": "// código aquí", "type": "tsx" }
  }
}
Si equipo_id es null, se asigna automáticamente el equipo de la STUDIO_KEY.
Respuesta:
{
  "message": "Artefacto insertado correctamente",
  "request_id": "330482e2-...",
  "empresa_id": 1,
  "artefacto_insertado": {
    "id": 545,
    "titulo": "Mi Primera App",
    "equipo_id": 2,
    "fecha_creacion": "2026-04-30T20:21:51.588362+00:00"
  },
  "api_key": "puente_artifact_xxxxx"
}
Guarda id, public_id (obtenlo con /meta) y api_key inmediatamente. La api_key solo se muestra una vez.

Actualizar artefacto

PUT {BASE_URL}/studio/artefactos/{id}
Content-Type: application/json

{
  "titulo": "Nuevo nombre",
  "descripcion": "Nueva descripción",
  "app_content": { ... TODOS los archivos ... }
}
El PUT reemplaza todo el app_content. Si envías solo los archivos modificados, los demás se eliminan permanentemente.Flujo seguro: GET → modificar en memoria → PUT con todo el contenido.

Obtener metadatos (incluye public_id)

GET {BASE_URL}/studio/artefactos/{id}/meta
Respuesta:
{
  "request_id": "8789ad9e-...",
  "artefacto": {
    "id": 541,
    "titulo": "App Base",
    "public_id": "788517f2-a8e1-44dc-9667-d3a48eff6972",
    "equipo_id": 2,
    "empresa_id": 1,
    "fecha_creacion": "2026-04-30T17:59:02.631483+00:00"
  }
}
La URL pública final de la app es https://app.puente.xyz/public/{public_id}/.

Endpoints privados — Tablas

Listar tablas

GET {BASE_URL}/studio/tablas

Crear tabla

POST {BASE_URL}/studio/tablas
Content-Type: application/json

{
  "nombre": "pedidos",
  "descripcion": "Pedidos del CRM",
  "equipo_id": null,
  "columnas": [
    { "key": "cliente",  "label": "Cliente",  "tipo": "text",    "requerido": true },
    { "key": "monto",    "label": "Monto",    "tipo": "number",  "requerido": true },
    { "key": "fecha",    "label": "Fecha",    "tipo": "date",    "requerido": false },
    { "key": "activo",   "label": "Activo",   "tipo": "boolean", "requerido": false },
    { "key": "estado",   "label": "Estado",   "tipo": "select",  "requerido": true,
      "opciones": ["pendiente", "pagado", "enviado"] }
  ]
}
Tipos de columna:
TipoFormato
textstring
numbernumber (decimal soportado)
date"YYYY-MM-DD"
booleantrue / false (no strings)
selectstring de las opciones

Actualizar tabla

PUT {BASE_URL}/studio/tablas/{tabla_id}
Content-Type: application/json

{ "nombre": "nuevo_nombre", "descripcion": "nueva descripción" }

Leer filas

GET {BASE_URL}/studio/tablas/{tabla_id}/datos?limit=500&offset=0
Máximo limit=5000. Para datasets grandes, pagina con offset.

Insertar fila

POST {BASE_URL}/studio/tablas/{tabla_id}/datos
Content-Type: application/json

{
  "datos": {
    "cliente": "Ana",
    "monto": 1000,
    "fecha": "2026-04-29",
    "estado": "pendiente"
  }
}

Insertar en masa (bulk)

POST {BASE_URL}/studio/tablas/{tabla_id}/datos/bulk
Content-Type: application/json

{
  "filas": [
    { "cliente": "Ana", "monto": 1000 },
    { "cliente": "Luis", "monto": 2500 }
  ]
}
Máximo 10,000 filas por request. Atómico: si una fila falla, ninguna se inserta.

API Keys de artefactos

Cada artefacto tiene su propia api_key (puente_artifact_xxx) que le permite conectarse a tablas desde el frontend sin JWT.

Obtener configuración (sin la key en texto plano)

GET {BASE_URL}/studio/artefactos/{id}/api-key
Respuesta:
{
  "id": 456,
  "artefacto_id": 123,
  "tipo": "artifact",
  "rate_limit_config": {
    "requests_per_minute": 60,
    "requests_per_hour": 1000,
    "requests_per_day": 10000
  },
  "revoked": false,
  "uso_count": 12543,
  "last_used_at": "2026-04-29T14:23:45Z"
}

Actualizar rate limit

PUT {BASE_URL}/studio/artefactos/{id}/api-key
Content-Type: application/json

{
  "rate_limit_config": {
    "requests_per_minute": 120,
    "requests_per_hour": 5000,
    "requests_per_day": 50000
  }
}

Regenerar API Key

OPERACIÓN DESTRUCTIVA. La key anterior queda invalidada inmediatamente. Cualquier app que la use deja de funcionar hasta actualizar el código.
POST {BASE_URL}/studio/artefactos/{id}/api-key/regenerate
Respuesta:
{
  "api_key": "puente_artifact_NEW_KEY_HERE",
  "message": "API key regenerada exitosamente. Guárdala de forma segura, no se podrá recuperar."
}

Acceso de artefactos a tablas

Un artefacto no puede leer/escribir una tabla por default. Hay que conceder acceso explícito.

Listar tablas accesibles

GET {BASE_URL}/studio/artefactos/{id}/tablas-acceso

Conceder acceso

POST {BASE_URL}/studio/artefactos/{id}/tablas-acceso
Content-Type: application/json

{ "tabla_id": "uuid-tabla", "permisos": ["read", "write"] }
Permisos disponibles:
["read"]                     // Solo lectura
["read", "write"]            // Lectura + insertar/actualizar
["read", "write", "delete"]  // Control total
Aplica principio de mínimo privilegio: un dashboard de consulta solo necesita ["read"].

Actualizar permisos

PUT {BASE_URL}/studio/artefactos/{id}/tablas-acceso/{tabla_id}
Content-Type: application/json

{ "permisos": ["read"] }

Revocar acceso

DELETE {BASE_URL}/studio/artefactos/{id}/tablas-acceso/{tabla_id}
La tabla debe pertenecer al mismo equipo que el artefacto.

Endpoints públicos — Datos del artefacto

Los usa la app publicada desde el frontend. Se autentican con la api_key del artefacto. Base URL: {BASE_URL}/public/artefacto/{artefacto_id} Auth: X-API-Key: puente_artifact_xxxxxxxxxxxx

Obtener metadatos de tabla

GET /public/artefacto/{artefacto_id}/tablas/{tabla_id}
Permiso requerido: read.

Listar filas (con filtros)

GET /public/artefacto/{artefacto_id}/tablas/{tabla_id}/datos?limit=50&offset=0
Permiso requerido: read.

Filtros con where

?where=(campo,operador,valor)~and(campo2,operador2,valor2)
Operadores:
OperadorDescripción
eq / neqIgual / no igual
gt / gte / lt / lteComparaciones numéricas
like / nlikeContiene / no contiene (case-insensitive)
starts / endsEmpieza / termina con
is / isnotEs null, notnull, true, false
in / notinEn lista / no en lista
empty / notemptyNulo o vacío / no
Operadores lógicos: ~and, ~or. Ejemplos:
?where=(plan,eq,Pro)~and(activo,is,true)
?where=(monto,gte,1000)~and(monto,lte,5000)
?where=(activo,is,true)&limit=20&offset=40
Si el valor contiene espacios o caracteres especiales, URL-encodea el parámetro completo.
Respuesta:
[
  {
    "id": "uuid-fila",
    "tabla_id": "uuid-tabla",
    "fila_data": {
      "fecha": "2026-04-29",
      "sucursal": "Santiago",
      "monto": 1250000
    },
    "created_at": "2026-04-29T12:00:00Z"
  }
]
El campo de datos se llama fila_data, no datos. Es un gotcha frecuente.

Headers de rate limit en respuesta

X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1709988123

Insertar fila

POST /public/artefacto/{artefacto_id}/tablas/{tabla_id}/dato
Content-Type: application/json

{ "datos": { "campo": "valor", "monto": 1000 } }
Permiso requerido: write.

Actualizar fila

PUT /public/artefacto/{artefacto_id}/tablas/{tabla_id}/dato/{fila_id}
Content-Type: application/json

{ "datos": { "monto": 2000 } }
Permiso requerido: write.

Eliminar fila

DELETE /public/artefacto/{artefacto_id}/tablas/{tabla_id}/dato/{fila_id}
Permiso requerido: delete.

Límites del sistema

ConceptoLímite
API keys activas por artefacto1
Tablas accesibles por artefactoIlimitado
Filas retornadas por request (pública)500 max
Filas retornadas por request (privada)5,000 max
Bulk insert10,000 filas por request
Rate limit default / minuto60 requests
Rate limit default / hora1,000 requests
Rate limit default / día10,000 requests

Códigos de error

Con STUDIO_KEY (gestión)

CódigoSignificadoQué hacer
401STUDIO_KEY inválida o revocadaGenerar nueva en app.puente.xyz → Configuración
403Sin créditosContactar admin de la cuenta
404Recurso no existe en tu equipoVerificar ID con endpoint de listado
422Campo con formato incorrectoLeer mensaje — indica qué campo falló

Con API Key de artefacto (públicos)

CódigoCausaSolución
400 Datos inválidosTipos incorrectos o requerido faltanteRevisar schema de columnas
401 API Key requeridaFalta headerIncluir X-API-Key: puente_artifact_xxx
401 API Key inválidaKey incorrecta, revocada o tipo incorrectoVerificar o regenerar
401 API Key no autorizadaKey pertenece a otro artefactoUsar la key correcta
403 Acceso no configuradoEl artefacto no tiene acceso a esa tablaPOST .../tablas-acceso
403 Permiso insuficientePermisos no incluyen la acciónPUT .../tablas-acceso/{tabla_id}
429 Rate limit excedidoDemasiados requestsEsperar Retry-After segundos

Ejemplo en JavaScript (dentro de una app publicada)

const API_KEY      = 'puente_artifact_xxxxxxxxxxxx';
const ARTEFACTO_ID = 123;
const TABLA_ID     = 'uuid-de-la-tabla';
const BASE         = `https://puente-backend-721178029791.southamerica-west1.run.app/public/artefacto/${ARTEFACTO_ID}`;

// Leer datos con filtro
const res = await fetch(
  `${BASE}/tablas/${TABLA_ID}/datos?where=(activo,is,true)&limit=50`,
  { headers: { 'X-API-Key': API_KEY } }
);
const filas = await res.json();

// Insertar fila
await fetch(`${BASE}/tablas/${TABLA_ID}/dato`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
  body: JSON.stringify({ datos: { nombre: 'Ana', monto: 100, fecha: '2026-04-29' } })
});

// Manejar rate limit
if (res.status === 429) {
  const retryAfter = res.headers.get('Retry-After') || 60;
  console.warn(`Rate limit excedido. Reintentar en ${retryAfter}s`);
}
La api_key del artefacto es visible en el código fuente de la app publicada (el bundle se sirve al browser del usuario). Usa siempre el mínimo privilegio (["read"] si solo lees) para limitar el riesgo si la key se filtra.