Guía completa para usar xltoapi y convertir tus Google Sheets en APIs REST.
Ve a Conexiones → Nueva conexión y pega la URL o ID de tu Google Sheet. Asegúrate de que la primera fila contenga los nombres de las columnas (headers).
Ejemplo de URL: https://docs.google.com/spreadsheets/d/abc123/edit
curl https://xltoapi.com/api/v1/sheets/TU_CONEXION_ID \ -H "x-api-key: xlta_tu_clave_aqui"
Todas las solicitudes a la API requieren una clave API en el header x-api-key.
// Header requerido en todas las solicitudes x-api-key: xlta_tu_clave_aqui
Las claves tienen permisos (scopes): read, write, delete. Cada endpoint requiere el scope correspondiente.
Base URL
https://xltoapi.com/api/v1/sheets/{connectionId}Reemplaza {connectionId} con el ID de tu conexión (lo encuentras en el dashboard).
Por defecto, cada conexión apunta a la hoja (pestaña) configurada al momento de crearla. Para acceder a otras pestañas del mismo spreadsheet, agrega /tabs/{nombrePestaña} a la URL:
# Hoja por defecto (configurada en la conexión) curl "https://xltoapi.com/api/v1/sheets/ID" \ -H "x-api-key: xlta_TU_CLAVE" # Pestaña específica curl "https://xltoapi.com/api/v1/sheets/ID/tabs/Ventas" \ -H "x-api-key: xlta_TU_CLAVE" # Pestaña con espacios (URL-encoded) curl "https://xltoapi.com/api/v1/sheets/ID/tabs/Hoja%201" \ -H "x-api-key: xlta_TU_CLAVE"
Todas las sub-rutas funcionan igual con /tabs/{nombrePestaña}:
| Ruta | Descripción |
|---|---|
| /tabs/{tab} | CRUD (GET, POST, PUT, PATCH, DELETE) |
| /tabs/{tab}/info | Info de columnas y metadata |
| /tabs/{tab}/row/{rango} | Fila o rango específico |
| /tabs/{tab}/search?col=val | Búsqueda multi-columna |
| /tabs/{tab}/filter/{col}/{val} | Filtro por URL |
| /tabs/{tab}/agg/{op}?column=col | Agregaciones |
| /tabs/{tab}/pivot/{col} | Tabla dinámica |
Hoja%201 para “Hoja 1”). Sin /tabs/, se usa la hoja configurada en la conexión.Retorna las filas de tu hoja de cálculo como JSON. Soporta filtros, paginación, ordenamiento y múltiples formatos.
curl "https://xltoapi.com/api/v1/sheets/ID?limit=10&sort=precio&order=desc" \ -H "x-api-key: xlta_..."
Respuesta:
{
"success": true,
"data": [
{ "_row": 2, "nombre": "Laptop", "precio": "1200", "stock": "15" },
{ "_row": 3, "nombre": "Mouse", "precio": "25", "stock": "200" }
],
"meta": { "total": 50, "limit": 10, "offset": 0, "format": "records" }
}El campo _row indica el número de fila en la hoja (la fila 1 son los headers, los datos empiezan en la fila 2).
Agrega una o varias filas al final de tu hoja. Envía un objeto para una fila o un array para varias.
// Una fila
curl -X POST "https://xltoapi.com/api/v1/sheets/ID" \
-H "x-api-key: xlta_..." \
-H "Content-Type: application/json" \
-d '{"nombre": "Teclado", "precio": "75", "stock": "50"}'
// Múltiples filas
curl -X POST "https://xltoapi.com/api/v1/sheets/ID" \
-H "x-api-key: xlta_..." \
-H "Content-Type: application/json" \
-d '[
{"nombre": "Monitor", "precio": "300", "stock": "20"},
{"nombre": "Webcam", "precio": "45", "stock": "80"}
]'Respuesta:
{ "success": true, "data": { "rows_added": 2 } }Reemplaza toda la fila. Los campos que no envíes quedarán vacíos. Debes incluir _row.
curl -X PUT "https://xltoapi.com/api/v1/sheets/ID" \
-H "x-api-key: xlta_..." \
-H "Content-Type: application/json" \
-d '{"_row": 3, "nombre": "Mouse Pro", "precio": "45", "stock": "150"}'Respuesta:
{ "success": true, "data": { "updated_row": 3, "mode": "full" } }{"_row": 3, "nombre": "Mouse Pro"}, las columnas precio y stock quedarán vacías. Para actualizar solo algunos campos, usa PATCH.Actualiza solo los campos que envíes. Los demás se mantienen sin cambios. Debes incluir _row.
curl -X PATCH "https://xltoapi.com/api/v1/sheets/ID" \
-H "x-api-key: xlta_..." \
-H "Content-Type: application/json" \
-d '{"_row": 3, "precio": "55"}'Respuesta:
{ "success": true, "data": { "updated_row": 3, "mode": "partial" } }Solo se actualiza precio. Las columnas nombre, stock, etc. no se modifican.
Elimina una fila de la hoja. La fila se elimina completamente (no solo se vacía).
curl -X DELETE "https://xltoapi.com/api/v1/sheets/ID" \
-H "x-api-key: xlta_..." \
-H "Content-Type: application/json" \
-d '{"_row": 3}'Respuesta:
{ "success": true, "data": { "deleted_row": 3 } }_row cambiarán. Si necesitas eliminar varias filas, hazlo de la última a la primera, o usa el endpoint DELETE por filtro.Filtra filas por valor exacto usando filter[columna]=valor. Puedes combinar múltiples filtros.
# Filtro simple GET /api/v1/sheets/ID?filter[categoria]=Electrónica # Múltiples filtros (AND) GET /api/v1/sheets/ID?filter[categoria]=Electrónica&filter[marca]=Samsung
Usa * como comodín para búsquedas parciales.
filter[nombre]=*laptop* — Contiene 'laptop'filter[nombre]=Mac* — Empieza con 'Mac'filter[nombre]=*Pro — Termina con 'Pro'# Productos que contienen "pro" (case-insensitive) GET /api/v1/sheets/ID?filter[nombre]=*pro*&search_ci=true
Usa query[columna]=__operador(valor) para comparaciones numéricas.
| Operador | Descripción | Ejemplo |
|---|---|---|
__eq(n) | Igual a | query[stock]=__eq(0) |
__ne(n) | Diferente de | query[stock]=__ne(0) |
__gt(n) | Mayor que | query[precio]=__gt(100) |
__gte(n) | Mayor o igual | query[precio]=__gte(100) |
__lt(n) | Menor que | query[stock]=__lt(10) |
__lte(n) | Menor o igual | query[stock]=__lte(10) |
# Productos con precio > 100 y stock < 10 GET /api/v1/sheets/ID?query[precio]=__gt(100)&query[stock]=__lt(10) # Combinar con filtros de texto GET /api/v1/sheets/ID?filter[categoria]=Electrónica&query[precio]=__lte(500)
Agrega search_ci=true para que las búsquedas no distingan entre mayúsculas y minúsculas. Aplica a filtros exactos, wildcards y búsqueda por URL.
# "juan", "Juan", "JUAN" todos coinciden GET /api/v1/sheets/ID?filter[nombre]=juan&search_ci=true
limit=10 — Máximo de filas a retornar (default: 100)offset=20 — Saltar las primeras N filas (default: 0)sort=precio — Ordenar por esta columnaorder=asc|desc — Dirección del orden (default: asc)# Página 3 con 10 resultados por página, ordenado por precio descendente GET /api/v1/sheets/ID?limit=10&offset=20&sort=precio&order=desc
El ordenamiento es inteligente: si los valores son numéricos, ordena numéricamente (9 < 10). Si son texto, ordena alfabéticamente.
Obtén una fila específica o un rango de filas directamente por su número.
# Fila específica GET /api/v1/sheets/ID/row/2 # Rango de filas (2, 3, 4, 5) GET /api/v1/sheets/ID/row/2:5
Respuesta (fila específica):
{
"success": true,
"data": { "_row": 2, "nombre": "Laptop", "precio": "1200", "stock": "15" }
}Respuesta (rango):
{
"success": true,
"data": [
{ "_row": 2, "nombre": "Laptop", "precio": "1200", "stock": "15" },
{ "_row": 3, "nombre": "Mouse", "precio": "25", "stock": "200" }
]
}La fila mínima es 2 (la fila 1 son los headers).
Forma simplificada de filtrar: /filter/{columna}/{valor}
# Filas donde categoria = "Electrónica" GET /api/v1/sheets/ID/filter/categoria/Electrónica # Con case-insensitive GET /api/v1/sheets/ID/filter/nombre/laptop?search_ci=true
Respuesta:
{
"success": true,
"data": [
{ "_row": 2, "nombre": "Laptop", "categoria": "Electrónica", "precio": "1200" }
],
"meta": { "total": 1 }
}Endpoint simplificado para buscar por múltiples columnas. Los parámetros de búsqueda son directos (sin filter[]).
# Buscar por nombre y categoría GET /api/v1/sheets/ID/search?nombre=Laptop&categoria=Electrónica # Con paginación y case-insensitive GET /api/v1/sheets/ID/search?marca=samsung&search_ci=true&limit=5&sort=precio
Parámetros reservados (no se usan como campos de búsqueda): search_ci, limit, offset, sort, order.
Elimina todas las filas que coincidan con el filtro. Útil para eliminar varios registros a la vez sin conocer los números de fila.
# Eliminar todas las filas donde estado = "inactivo" curl -X DELETE "https://xltoapi.com/api/v1/sheets/ID/filter/estado/inactivo" \ -H "x-api-key: xlta_..." # Case-insensitive curl -X DELETE "https://xltoapi.com/api/v1/sheets/ID/filter/estado/INACTIVO?search_ci=true" \ -H "x-api-key: xlta_..."
Respuesta:
{ "success": true, "data": { "deleted_rows": 5 } }Calcula operaciones matemáticas sobre las columnas numéricas de tu hoja.
| Operación | Descripción |
|---|---|
sum | Suma total |
max | Valor máximo |
min | Valor mínimo |
mean | Promedio |
median | Mediana |
count | Cantidad de valores numéricos |
# Suma de la columna "precio" GET /api/v1/sheets/ID/agg/sum?column=precio # Promedio de todas las columnas numéricas GET /api/v1/sheets/ID/agg/mean
Respuesta:
{
"success": true,
"data": {
"operation": "sum",
"column": "precio",
"result": { "precio": 15750 }
}
}Si no envías column, la operación se aplica a todas las columnas que contengan datos numéricos. Las columnas sin datos numéricos retornan null.
Obtén estadísticas detalladas de cada columna de tu hoja.
GET /api/v1/sheets/ID/info
Respuesta:
{
"success": true,
"data": {
"totalRows": 150,
"totalColumns": 5,
"columns": {
"nombre": {
"count": 150,
"unique": 120,
"nulls": 0
},
"precio": {
"count": 148,
"unique": 45,
"nulls": 2,
"numeric": {
"mean": 350.5,
"std": 125.3,
"min": 10,
"max": 1500,
"p25": 99,
"p50": 250,
"p75": 499
}
}
}
}
}Para cada columna: count (valores no vacíos), unique (valores únicos), nulls (celdas vacías). Si la columna tiene datos numéricos, incluye estadísticas adicionales con percentiles.
Agrupa datos por una columna y aplica una operación de agregación. Similar a las tablas dinámicas de Excel.
_agg=sum|max|min|mean|count — Operación de agregación (default: count)_value=columna — Columna sobre la que operar (default: todas las numéricas)# Contar productos por categoría GET /api/v1/sheets/ID/pivot/categoria # Suma de ventas por región GET /api/v1/sheets/ID/pivot/region?_agg=sum&_value=ventas # Precio promedio por marca GET /api/v1/sheets/ID/pivot/marca?_agg=mean&_value=precio
Respuesta:
{
"success": true,
"data": {
"groupBy": "categoria",
"aggregation": "sum",
"valueColumn": "precio",
"result": {
"Electrónica": { "precio": 8500 },
"Ropa": { "precio": 3200 },
"Hogar": { "precio": 4050 }
}
}
}Usa _format para cambiar el formato del JSON retornado por el GET principal.
| Formato | Descripción |
|---|---|
records | Array de objetos (default) |
dict | Objeto de objetos: {columna: {fila: valor}} |
list | Columnas como arrays: {columna: [valores]} |
split | Separado: {columns: [], data: [][], index: []} |
# Formato dict
GET /api/v1/sheets/ID?_format=dict
// { "nombre": { "2": "Laptop", "3": "Mouse" }, "precio": { "2": "1200", "3": "25" } }
# Formato list
GET /api/v1/sheets/ID?_format=list
// { "nombre": ["Laptop", "Mouse"], "precio": ["1200", "25"] }
# Formato split
GET /api/v1/sheets/ID?_format=split
// { "columns": ["nombre", "precio"], "data": [["Laptop", "1200"], ["Mouse", "25"]], "index": [2, 3] }Agrega _raw=1 para obtener los datos como un array de arrays, sin el wrapping de success/data/meta. La primera fila son los headers.
GET /api/v1/sheets/ID?_raw=1
Respuesta:
[ ["nombre", "precio", "stock"], ["Laptop", "1200", "15"], ["Mouse", "25", "200"], ["Teclado", "75", "50"] ]
Se puede combinar con filtros, paginación y ordenamiento: ?_raw=1&sort=precio&order=desc&limit=5
Inserta una tabla con los datos de tu hoja en cualquier página web con una sola línea de código. Sin dependencias, sin frameworks — solo un <script>.
<!-- Agrega esto donde quieras mostrar la tabla --> <div id="xltoapi-table"></div> <script src="https://xltoapi.com/api/v1/embed?id=TU_CONEXION_ID&key=xlta_tu_clave"></script>
id — (requerido) ID de tu conexiónkey — (requerido) Tu clave APItheme=light|dark — Tema visual (default: light)limit=100 — Máximo de filas a mostrartitle=Mis datos — Título opcional sobre la tablatarget=mi-div — ID del elemento HTML donde renderizar (default: xltoapi-table)Ejemplo con tema oscuro y título:
<div id="productos"></div> <script src="https://xltoapi.com/api/v1/embed?id=abc123&key=xlta_xxx&theme=dark&title=Productos&target=productos&limit=20"></script>
Ejemplo completo:
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Mi página</title> </head> <body> <h1>Inventario</h1> <p>Datos actualizados en tiempo real desde Google Sheets:</p> <div id="xltoapi-table"></div> <script src="https://xltoapi.com/api/v1/embed?id=TU_ID&key=xlta_xxx&theme=light&title=Inventario&limit=50"></script> </body> </html>
Todas las respuestas GET incluyen headers con información útil.
| Header | Descripción |
|---|---|
X-RateLimit-Limit | Límite de solicitudes por minuto |
X-RateLimit-Remaining | Solicitudes restantes en este minuto |
X-RateLimit-Reset | Timestamp (epoch) cuando se resetea el contador |
X-Sheet-Rows | Total de filas de datos en la hoja |
X-Sheet-Columns | Total de columnas en la hoja |
Cada plan tiene límites de solicitudes por minuto y por mes. Al exceder el límite, recibirás un error 429.
| Plan | Por minuto | Por mes |
|---|---|---|
| Gratis | 30 | 1,000 |
| Pro | 120 | 50,000 |
| Empresarial | 600 | 500,000 |
// Error 429
{
"success": false,
"error": "Rate limit exceeded",
"mensaje": "Límite de solicitudes excedido"
}Copia esta plantilla para mostrar datos de tu API en cualquier página web:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mis datos</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #f5f5f5; font-weight: 600; }
tr:hover { background: #f9f9f9; }
</style>
</head>
<body>
<h1>Mis datos</h1>
<table>
<thead><tr id="headers"></tr></thead>
<tbody id="body"></tbody>
</table>
<script>
const API_URL = "https://xltoapi.com/api/v1/sheets/TU_ID";
const API_KEY = "xlta_tu_clave";
fetch(API_URL, { headers: { "x-api-key": API_KEY } })
.then(res => res.json())
.then(({ data }) => {
if (!data.length) return;
const keys = Object.keys(data[0]).filter(k => k !== "_row");
document.getElementById("headers").innerHTML =
keys.map(k => `<th>${k}</th>`).join("");
document.getElementById("body").innerHTML =
data.map(row =>
"<tr>" + keys.map(k => `<td>${row[k] ?? ""}</td>`).join("") + "</tr>"
).join("");
});
</script>
</body>
</html>| Método | Endpoint | Descripción |
|---|---|---|
| GET | /sheets/{id} | Listar filas con filtros |
| POST | /sheets/{id} | Agregar filas |
| PUT | /sheets/{id} | Reemplazar fila completa |
| PATCH | /sheets/{id} | Actualización parcial |
| DELETE | /sheets/{id} | Eliminar fila por _row |
| GET | /sheets/{id}/row/{n} | Fila por índice |
| GET | /sheets/{id}/row/{n:m} | Rango de filas |
| GET | /sheets/{id}/filter/{col}/{val} | Filtrar por URL |
| DELETE | /sheets/{id}/filter/{col}/{val} | Eliminar por filtro |
| GET | /sheets/{id}/search | Búsqueda multi-columna |
| GET | /sheets/{id}/agg/{op} | Agregaciones |
| GET | /sheets/{id}/info | Estadísticas por columna |
| GET | /sheets/{id}/pivot/{col} | Tabla dinámica |
| GET | /embed?id=...&key=... | SDK JS embebible |