Introducción a PraxQL
Vincent Depassier · 29 de agosto de 2026
PraxQL — Introducción
PraxQL es el lenguaje de consulta declarativo de Praxsuite, basado en JSON. Es lo que usás para leer y escribir datos a través del API Gateway. En vez de configurar un endpoint REST por cada patrón de acceso, mandás un único cuerpo JSON estructurado que describe exactamente lo que querés.
Por qué existe PraxQL
Las tablas de Praxsuite las crean los usuarios en tiempo de ejecución, no las define un desarrollador al desplegar. La forma de un workspace cambia cada vez que alguien agrega una tabla o renombra una columna, y es distinta de la de cualquier otro workspace.
Eso descarta las opciones de estante. GraphQL quiere un esquema fijo al momento de desplegar. Las capas REST autogeneradas asumen una estructura estable y segura de exponer. OData no describe un esquema que cambia por tenant y se modifica mientras el servicio corre.
PraxQL se construyó para esa situación: un endpoint, un formato de request, y un esquema que descubrís en runtime en vez de uno contra el que compilás.
La forma del request
Toda llamada PraxQL es un POST a un solo endpoint:
POST https://gateway.praxsuite.com/{workspaceId}/query
Authorization: Bearer sk_live_xxxxx
Content-Type: application/jsonEsa forma corta es la que conviene usar. El gateway también responde la ruta larga /api/v1/gateway/{workspaceId}/query, que es la que vas a ver en ejemplos viejos — mismo endpoint, mismo cuerpo.
El cuerpo siempre tiene dos partes:
{
"refs": {
"Alias": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"query": { ... }
}O, para escrituras:
{
"refs": {
"Alias": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"mutation": { ... }
}query y mutation son mutuamente excluyentes.
refs — el diccionario de tablas
El objeto refs mapea los alias que elegís vos a GUIDs de tabla. Existe porque los nombres de tabla no son únicos: un workspace puede tener varias tablas llamadas "Clientes" en distintos momentos, así que un nombre no alcanza para identificar una.
{
"refs": {
"Clientes": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Pedidos": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
}Reglas:
Las claves son cualquier string que elijas — pasan a ser tu alias dentro de
query/mutation.Los valores son los GUID de tabla. Los sacás del panel de esquema del Playground o de
GET /schema.Todo GUID debe pertenecer al workspace autenticado. Una referencia a una tabla de otro workspace se rechaza.
Hasta 20 refs por request.
refs es además la lista completa de lo que un request puede tocar, que es lo que le permite al gateway contrastarlo con tus permisos antes de hacer ningún trabajo.
query vs mutation
Clave | Operaciones | Cuándo |
| Leer | Traer registros, filtrar, agregar, unir |
| Escribir | Insertar filas, actualizar campos, eliminar registros |
Opcional: includeTotalCount
Por defecto la respuesta no trae el total de filas que matchean — se omite porque cuesta una segunda pasada sobre los datos. Para pedirlo:
{
"refs": { ... },
"query": { ... },
"includeTotalCount": true
}Pedilo solo cuando estés dibujando controles de paginación que muestran un total; un botón de "siguiente" no lo necesita.
La forma de la respuesta
{
"data": [
{ "Nombre": "Acme Corp", "Email": "hola@acme.com" },
{ "Nombre": "Beta Inc", "Email": "info@beta.io" }
],
"meta": {
"count": 2,
"limit": 50,
"offset": 0,
"total": null,
"durationMs": 4
}
}Campo | Significado |
| Array de filas. Las claves son nombres lógicos de columna. |
| Cantidad de filas en esta respuesta |
| El límite efectivo aplicado |
| El offset aplicado |
| Total de filas que matchean — solo con |
| Tiempo de ejecución, sin contar la autenticación |
Conviene leer meta.limit en vez de asumirlo: el límite efectivo puede ser menor que el que pediste.
Errores
{
"error": {
"code": "INVALID_QUERY",
"message": "Column 'Emaill' not found in table 'Clientes'.",
"details": ["Available columns: Nombre, Email, Telefono, Estado"]
}
}HTTP | Código | Causa |
|
| Consulta malformada, columna desconocida, operador inválido |
|
| GUID desconocido, de otro workspace, o refs vacío |
|
| API key inválida o ausente |
|
| Tabla o columna fuera de permisos, agregación no permitida |
|
| Key revocada o vencida, o principal suspendido |
|
| La consulta superó los 30 segundos |
|
| La key superó su cuota |
|
| Error interno, registrado del lado del servidor |
SCOPE_VIOLATION merece entenderse: una tabla para la que tu key no tiene permiso responde 403, no 404, y el mensaje no confirma si la tabla existe. Es deliberado — un 404 permitiría mapear tu workspace probando GUIDs.
Qué le pasa a un request
Toda llamada se autentica, se contrasta con los permisos de la credencial que la mandó, se traduce de los nombres lógicos que usaste a lo que la capa de almacenamiento necesita, se ejecuta, y se vuelve a filtrar a la salida para aplicar las reglas de enmascarado.
Lo último importa para cómo diseñás tus consultas: los permisos se aplican a la entrada y a la salida. Una columna sobre la que podés filtrar pero no leer participa igual del where sin aparecer nunca en la respuesta.
Todo request queda además registrado en el log de auditoría — incluidos los que fallaron.