API pública de presupuestaIA
API REST de solo lectura que expone los datos sincronizados de cada empresa (clientes, artículos, obras y avisos correctivo). Pensada para integraciones con ERPs externos, paneles BI o procesos automáticos. Una API key habilita el acceso a una empresa concreta; los datos están aislados por empresa.
Base URL
https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1
Sandbox de pruebas
Antes de pedir tu API key real, puedes probar tu integración contra endpoints sandbox que devuelven datos ficticios fijos y no requieren autenticación. Útil para desarrollar y validar que tu código procesa bien la respuesta antes de pasar a producción.
/v1/sandbox/clientes
/v1/sandbox/articulos
/v1/sandbox/obras
/v1/sandbox/avisos-correctivo
Pruébalo ya — copia y pega:
curl https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1/v1/sandbox/clientes
O ábrelo en el navegador:
🌐 Abrir /v1/sandbox/clientesCuando funcione, pasa a producción:
- Pide tu API key real al admin de tu empresa (panel Integraciones).
- Cambia la URL:
/v1/sandbox/clientes→/v1/clientes. - Añade el header:
Authorization: Bearer pia_…
Las respuestas reales tienen el mismo formato que las del sandbox. Solo cambia el
contenido (datos reales en vez de ficticios) y desaparece el flag "sandbox": true.
Autenticación
Cada llamada debe enviar la API key de la empresa en el header Authorization.
La key te la entregará el administrador de la empresa una sola vez al
generarla, con formato pia_<prefix>_<secret>.
Authorization: Bearer pia_a1b2c3d4_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Alternativa equivalente: header X-API-Key: pia_….
⚠️ La key concede acceso a todos los datos de la empresa. Trátala como una contraseña: no la subas a un repositorio público, no la compartas por email, y revócala si crees que se ha filtrado.
Endpoints
Cada item devuelto incluye los campos destacados normalizados (cómodos para usar) más el objeto data con la fila íntegra original proveniente del ERP (~150 columnas en clientes, etc.).
Esto significa que no hay ningún campo del ERP que quede fuera del API: si no aparece en los campos destacados, lo encuentras dentro de data.
/v1/clientes
· listado
Lista los clientes sincronizados de la empresa.
Cada item:
{
"id_velneo": "string",
"nombre": "string",
"cif": "string",
"email": "string",
"telefono": "string",
"direccion": "string",
"data": { /* fila íntegra del ERP, ~150 campos:
"01_NOMBRE_COMERCIAL", "06_CIF", "07_DOMICILIO",
"08_CIUDAD", "09_PROVINCIA", "12_CPOSTAL",
"WWW", "PORCENTAJE_RETENCION", … */ },
"actualizado_at": "ISO 8601 timestamp"
}
/v1/clientes/:id_velneo
· detalle
Devuelve un cliente concreto con todos sus campos. :id_velneo es el ID del ERP.
{
"ok": true,
"item": { /* mismo formato que en el listado, con `data` íntegro */ }
}
/v1/articulos
· listado · detalle en /v1/articulos/:id_velneo
Catálogo de artículos sincronizado.
{
"id_velneo": "string",
"codigo": "string",
"nombre": "string",
"unidad": "string",
"precio": "number",
"data": { /* todas las columnas del ERP: familia, proveedor, marca,
stock mínimo/máximo, ecotasa, precios margen,
fotos, observaciones, … */ },
"actualizado_at": "ISO 8601 timestamp"
}
/v1/obras
· listado · detalle en /v1/obras/:id_velneo
Listado de obras de la empresa.
{
"id_velneo": "string",
"codigo": "string",
"nombre": "string",
"descripcion": "string",
"cliente_id_velneo": "string",
"estado": "string",
"data": { /* todos los campos: importes presupuestados/reales,
fechas, contactos, dirección, persona de contacto,
documentos, etc. */ },
"actualizado_at": "ISO 8601 timestamp"
}
/v1/avisos-correctivo
· listado · detalle en /v1/avisos-correctivo/:id_velneo
Avisos / partes correctivos.
{
"id_velneo": "string",
"codigo": "string",
"fecha": "YYYY-MM-DD",
"cliente_id_velneo": "string",
"obra_id_velneo": "string",
"descripcion": "string",
"estado": "string",
"prioridad": "string",
"data": { /* todos los campos: técnico asignado, hora cita,
coste mano de obra, coste material, contrato
mantenimiento, ruta, etc. */ },
"actualizado_at": "ISO 8601 timestamp"
}
Parámetros de query
Todos los endpoints aceptan los mismos parámetros opcionales:
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
limit | int (1-1000) | 100 | Tamaño de página |
offset | int | 0 | Para paginar tras el primer batch |
updated_since | ISO 8601 | — | Solo registros modificados desde esa fecha (sync incremental) |
Formato de respuesta
Listados:
{
"ok": true,
"total": 1268,
"limit": 100,
"offset": 0,
"has_more": true,
"next_offset": 100,
"items": [ /* … */ ]
}
total es el total de registros disponibles tras aplicar filtros (no la cuenta de items).
Para iterar todo basta seguir next_offset mientras has_more sea true.
Detalle (/v1/<recurso>/:id_velneo):
{
"ok": true,
"item": { /* el registro con `data` íntegro */ }
}
Códigos de error
| HTTP | error | Causa |
|---|---|---|
401 | auth_required | Falta header Authorization |
401 | unauthorized | Key inválida o revocada |
404 | not_found | Endpoint inexistente |
405 | method_not_allowed | Solo se permite GET |
500 | — | Error interno; reintentar tras unos segundos |
Ejemplos
curl · listado
curl -H "Authorization: Bearer pia_a1b2c3d4_xxxxxxxxxxxx" \
"https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1/v1/clientes?limit=50"
curl · detalle de un cliente
curl -H "Authorization: Bearer pia_a1b2c3d4_xxxxxxxxxxxx" \
"https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1/v1/clientes/1234"
Devuelve item.data con TODAS las columnas originales del ERP.
Sync incremental (solo cambios de hoy)
curl -H "Authorization: Bearer pia_a1b2c3d4_xxxxxxxxxxxx" \
"https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1/v1/avisos-correctivo?updated_since=2026-05-06T00:00:00Z"
Paginación completa (Node.js)
const KEY = process.env.PIA_API_KEY
const BASE = 'https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1'
async function obtenerTodos(recurso) {
const items = []
let offset = 0
while (true) {
const r = await fetch(`${BASE}/v1/${recurso}?limit=1000&offset=${offset}`, {
headers: { Authorization: `Bearer ${KEY}` },
})
if (!r.ok) throw new Error(`HTTP ${r.status}`)
const { items: batch, has_more, next_offset } = await r.json()
items.push(...batch)
if (!has_more) break
offset = next_offset
}
return items
}
const clientes = await obtenerTodos('clientes')
console.log(`${clientes.length} clientes`)
// Acceder a cualquier campo Velneo:
console.log(clientes[0].data['07_DOMICILIO'], clientes[0].data['12_CPOSTAL'])
Python (requests)
import os, requests
KEY = os.environ['PIA_API_KEY']
BASE = 'https://bydakfftxdorkkswixoa.supabase.co/functions/v1/api-public-v1'
r = requests.get(
f'{BASE}/v1/articulos',
headers={'Authorization': f'Bearer {KEY}'},
params={'limit': 500},
)
r.raise_for_status()
print(r.json()['total'], 'artículos disponibles')
Frecuencia de actualización
Los datos se actualizan cuando el administrador de la empresa
sube los CSV exportados de su ERP desde el panel de gestión (sustituye
por completo el contenido anterior). Usa el campo actualizado_at
o el parámetro updated_since para detectar cambios.
Buenas prácticas
- Usa
updated_sincecon un timestamp guardado de tu última sync para no descargar todo cada vez. - Pagina siguiendo
next_offsethasta quehas_more = false. Tamaño recomendadolimit=1000. - Si solo necesitas un registro concreto, usa el endpoint de detalle
/v1/<recurso>/:id_velneoen vez de filtrar el listado. - Los campos originales del ERP están dentro de
item.datacon los mismos nombres del CSV importado (p.ej.data["01_NOMBRE_COMERCIAL"],data["12_CPOSTAL"]). - Cachea las respuestas durante al menos 5 minutos: los datos no cambian más rápido que el cron.
- Si recibes
401 unauthorizedpersistente, comprueba que la key no esté revocada en el panel. - Reintenta los errores
5xxcon backoff exponencial (2s, 4s, 8s, máx. 5 intentos).