Documentación

Guía completa para usar xltoapi y convertir tus Google Sheets en APIs REST.

Inicio rápido

1. Inicia sesión con Google
Haz clic en "Comenzar gratis" y autoriza el acceso a tus hojas de Google Sheets. Necesitamos permisos de lectura/escritura para poder crear tu API.
2. Conecta tu hoja de cálculo

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

3. Crea una clave API
Ve a Claves API → Nueva clave. Selecciona los permisos (leer, escribir, eliminar) y copia la clave. Solo se muestra una vez.
4. Haz tu primera solicitud
curl https://xltoapi.com/api/v1/sheets/TU_CONEXION_ID \
  -H "x-api-key: xlta_tu_clave_aqui"

Autenticación

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).

Pestañas / Tabs

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}:

RutaDescripción
/tabs/{tab}CRUD (GET, POST, PUT, PATCH, DELETE)
/tabs/{tab}/infoInfo de columnas y metadata
/tabs/{tab}/row/{rango}Fila o rango específico
/tabs/{tab}/search?col=valBúsqueda multi-columna
/tabs/{tab}/filter/{col}/{val}Filtro por URL
/tabs/{tab}/agg/{op}?column=colAgregaciones
/tabs/{tab}/pivot/{col}Tabla dinámica
Nota: Si el nombre de la pestaña contiene espacios u otros caracteres especiales, usa URL-encoding (ej: Hoja%201 para “Hoja 1”). Sin /tabs/, se usa la hoja configurada en la conexión.

GET Obtener datos

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).

POST Agregar filas

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 } }

PUT Reemplazar fila completa

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" } }
Nota: Si solo envías {"_row": 3, "nombre": "Mouse Pro"}, las columnas precio y stock quedarán vacías. Para actualizar solo algunos campos, usa PATCH.

PATCH Actualización parcial

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.

DELETE Eliminar fila

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 } }
Importante: Al eliminar una fila, las filas debajo se desplazan hacia arriba. Los números de _row cambiarán. Si necesitas eliminar varias filas, hazlo de la última a la primera, o usa el endpoint DELETE por filtro.

Filtros y búsqueda

Filtros exactos

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

Wildcards (búsqueda parcial)

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

Operadores numéricos

Usa query[columna]=__operador(valor) para comparaciones numéricas.

OperadorDescripciónEjemplo
__eq(n)Igual aquery[stock]=__eq(0)
__ne(n)Diferente dequery[stock]=__ne(0)
__gt(n)Mayor quequery[precio]=__gt(100)
__gte(n)Mayor o igualquery[precio]=__gte(100)
__lt(n)Menor quequery[stock]=__lt(10)
__lte(n)Menor o igualquery[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)

Búsqueda case-insensitive

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

Paginación y ordenamiento

  • limit=10 Máximo de filas a retornar (default: 100)
  • offset=20 Saltar las primeras N filas (default: 0)
  • sort=precio Ordenar por esta columna
  • order=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.

Endpoints especiales

GET Fila por índice o rango

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).

GET Filtro por URL

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 }
}

DELETE Eliminar por filtro

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 } }
Cuidado: Esta operación no se puede deshacer. Las filas se eliminan de la hoja permanentemente.

Analítica

GET Agregaciones

Calcula operaciones matemáticas sobre las columnas numéricas de tu hoja.

OperaciónDescripción
sumSuma total
maxValor máximo
minValor mínimo
meanPromedio
medianMediana
countCantidad 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.

GET Info / Estadísticas

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.

GET Tablas dinámicas (Pivot)

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 }
    }
  }
}

Formatos de respuesta

Usa _format para cambiar el formato del JSON retornado por el GET principal.

FormatoDescripción
recordsArray de objetos (default)
dictObjeto de objetos: {columna: {fila: valor}}
listColumnas como arrays: {columna: [valores]}
splitSeparado: {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] }

Raw mode

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

SDK embebible

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>

Parámetros del script:

  • id (requerido) ID de tu conexión
  • key (requerido) Tu clave API
  • theme=light|dark Tema visual (default: light)
  • limit=100 Máximo de filas a mostrar
  • title=Mis datos Título opcional sobre la tabla
  • target=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>
Nota: El script se cachea por 5 minutos. Los datos se obtienen en cada carga de página. La tabla incluye estilos propios que no interfieren con los de tu sitio.

Headers de respuesta

Todas las respuestas GET incluyen headers con información útil.

HeaderDescripción
X-RateLimit-LimitLímite de solicitudes por minuto
X-RateLimit-RemainingSolicitudes restantes en este minuto
X-RateLimit-ResetTimestamp (epoch) cuando se resetea el contador
X-Sheet-RowsTotal de filas de datos en la hoja
X-Sheet-ColumnsTotal de columnas en la hoja

Rate limiting

Cada plan tiene límites de solicitudes por minuto y por mes. Al exceder el límite, recibirás un error 429.

PlanPor minutoPor mes
Gratis301,000
Pro12050,000
Empresarial600500,000
// Error 429
{
  "success": false,
  "error": "Rate limit exceeded",
  "mensaje": "Límite de solicitudes excedido"
}

Plantilla HTML

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>

Resumen de endpoints

MétodoEndpointDescripció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}/searchBúsqueda multi-columna
GET/sheets/{id}/agg/{op}Agregaciones
GET/sheets/{id}/infoEstadísticas por columna
GET/sheets/{id}/pivot/{col}Tabla dinámica
GET/embed?id=...&key=...SDK JS embebible

¿Tienes preguntas? Contáctanos en soporte@xltoapi.com