Documentación de la API
Recetas de integración con BI
Ejemplos listos para copiar y pegar que conectan herramientas de BI y entornos de ejecución comunes con la API de reportes de Saldo.tech. Cada receta asume que ya generaste una clave de API de la institución; si no, ve a Panel → Claves de API para crear una.
Consulta la referencia completa de endpoints y los detalles de autenticación en la documentación de la API.
cURL
La forma más rápida de verificar que tu clave funciona y explorar la estructura de las respuestas desde la terminal.
# Last 30 days of redemptions
curl https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/redemptions \
-H "Authorization: Bearer slk_..." \
| jq '.data | length'
# Filter by date range
curl "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/redemptions?from=2026-04-01T00:00:00Z&to=2026-05-01T00:00:00Z" \
-H "Authorization: Bearer slk_..."
# Engagement funnel for the last 7 days
FROM=$(date -u -v-7d +"%Y-%m-%dT%H:%M:%SZ")
curl "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/funnel?from=$FROM" \
-H "Authorization: Bearer slk_..."Python (requests + pandas)
Carga todos los canjes en un DataFrame para análisis ad hoc o ingesta en un pipeline. Gestiona la paginación automáticamente.
import os
import requests
import pandas as pd
API_KEY = os.environ["SALDO_API_KEY"]
BASE = "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting"
def fetch_all(path: str, params: dict | None = None) -> list[dict]:
rows: list[dict] = []
cursor = None
while True:
q = {"limit": 1000, **(params or {})}
if cursor:
q["cursor"] = cursor
r = requests.get(
f"{BASE}/{path}",
headers={"Authorization": f"Bearer {API_KEY}"},
params=q,
timeout=30,
)
r.raise_for_status()
body = r.json()
rows.extend(body["data"])
cursor = body["pagination"]["next_cursor"]
if not cursor:
return rows
# Last quarter's redemptions
redemptions = fetch_all(
"redemptions",
{"from": "2026-02-01T00:00:00Z", "to": "2026-05-01T00:00:00Z"},
)
df = pd.json_normalize(redemptions)
print(df.groupby("offer.merchant_name")["institution_payout_amount"].sum().sort_values(ascending=False))Node.js (fetch)
Iterador asíncrono listo para usar que pagina grandes conjuntos de resultados sin mantener todo en memoria.
const API_KEY = process.env.SALDO_API_KEY;
const BASE = "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting";
async function* paginate(path, params = {}) {
let cursor = null;
while (true) {
const url = new URL(`${BASE}/${path}`);
Object.entries({ limit: 1000, ...params }).forEach(([k, v]) =>
url.searchParams.set(k, String(v)),
);
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const body = await res.json();
for (const row of body.data) yield row;
cursor = body.pagination.next_cursor;
if (!cursor) return;
}
}
let total = 0;
for await (const settlement of paginate("settlements", { status: "settled" })) {
total += settlement.institution_payout_amount;
}
console.log(`Total settled payouts: $${total.toFixed(2)}`);Google Sheets (Apps Script)
Actualiza una hoja con los últimos KPI del embudo bajo demanda. Abre Extensiones → Apps Script y pega esto.
function refreshFunnel() {
const apiKey = PropertiesService.getScriptProperties().getProperty("SALDO_API_KEY");
const url = "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/funnel";
const res = UrlFetchApp.fetch(url, {
headers: { Authorization: "Bearer " + apiKey },
muteHttpExceptions: true,
});
const body = JSON.parse(res.getContentText());
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Funnel");
sheet.getRange("A1").setValue("Last refreshed");
sheet.getRange("B1").setValue(new Date());
sheet.getRange("A3:B3").setValues([["Metric", "Value"]]);
sheet.getRange("A4:B8").setValues([
["Widget Views", body.data.widget_views],
["Unique Cardholders", body.data.unique_cardholders],
["Offer Impressions", body.data.offer_impressions],
["Offer Adds", body.data.offer_add_successes],
["Redemptions", body.data.redemptions],
]);
}
// Set up: Project Settings → Script Properties → add SALDO_API_KEY
// Then Triggers → Add Trigger → refreshFunnel → Time-driven → daily.Power BI (Power Query M)
Conecta Power BI directamente a tu libro de liquidaciones como fuente de datos actualizable. Recorre el cursor automáticamente.
let
ApiKey = "slk_...",
BaseUrl = "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/settlements",
FetchPage = (cursor as nullable text) =>
let
Query = if cursor = null then [limit="1000"] else [limit="1000", cursor=cursor],
Source = Json.Document(Web.Contents(BaseUrl, [
Query = Query,
Headers = [#"Authorization" = "Bearer " & ApiKey]
]))
in Source,
Loop = List.Generate(
() => FetchPage(null),
each Record.HasFields(_, "data") and List.Count(_[data]) > 0,
each FetchPage(_[pagination][next_cursor]),
each _[data]
),
AllRows = List.Combine(Loop),
AsTable = Table.FromRecords(AllRows),
Typed = Table.TransformColumnTypes(AsTable, {
{"created_at", type datetimezone},
{"settled_at", type datetimezone},
{"merchant_funded_amount", Currency.Type},
{"saldo_revenue", Currency.Type},
{"institution_payout_amount", Currency.Type}
})
in
TypedMetabase (consulta HTTP)
Consulta HTTP nativa lista para usar con el controlador de solicitudes HTTP de Metabase. Funciona con cualquiera de los endpoints de reportes JSON.
{
"method": "GET",
"url": "https://saldo-consumer-api-git-staging-kalantech.vercel.app/api/v1/reporting/redemptions",
"headers": {
"Authorization": "Bearer {{secret_api_key}}"
},
"parameters": {
"from": "{{from_date}}",
"to": "{{to_date}}",
"limit": 1000
},
"result": {
"path": "data"
}
}
# Define a Metabase secret named secret_api_key holding your slk_... value.
# Pass from_date / to_date as Metabase parameters in the dashboard filter UI.
# Note: cursor pagination is single-page in this driver — for more than
# 1000 rows, use a scheduled ETL into a SQL warehouse Metabase can read.¿Necesitas una receta que no tenemos?
Cuéntanos qué stack de BI usas; estamos priorizando las integraciones más solicitadas a continuación.