Reference · v1

API

REST endpoints para conectar n8n, Zapier, scripts internos o cualquier worker con tu cuenta KANDIMA. JSON in, JSON out. Bearer auth con keys generadas desde el dashboard.

Autenticación

Generá una API key desde Dashboard → API Keys. El formato es ka_live_xxxxxxxx en producción y ka_test_xxxxxxxx en desarrollo.

Pasala como header Bearer:

Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
· La key se muestra completa una sola vez al crearla.
· Podés revocarla en cualquier momento desde el dashboard.
· Cada key tiene scopes (read, write).

Rate limiting

60 requests/minuto por API key. Cuando excedés el límite recibís 429 Too Many Requests. Cada respuesta incluye los headers:

X-RateLimit-Remaining: 59
X-RateLimit-Reset: 47

Necesitás más cuota? Contactanos.

Endpoints

GET/api/v1/statusscope: read

Health check público — no requiere Bearer auth. Útil para monitorear desde scripts antes de operar y evitar consumir quota durante outages. Cache 15s.

Request
curl https://kandima.ai/api/v1/status
Response · 200 OK
{
  "status": "operational",
  "api_version": "v1",
  "checks": {
    "database": { "status": "ok", "latency_ms": 42 }
  },
  "meta": {
    "region": "gru1",
    "env": "production",
    "commit": "7qjzCz5",
    "check_total_ms": 47
  },
  "ts": "2026-05-14T16:00:00Z"
}
GET/api/v1/mescope: read

Devuelve el perfil del usuario autenticado (plan, currency, timezone, fecha de creación) y los scopes activos de la API key.

Request
curl https://kandima.ai/api/v1/me \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "user_id": "user_3DaORih5ursagiFh35CZm41SMm1",
  "scopes": ["read", "write"],
  "profile": {
    "plan": "pro",
    "currency": "USD",
    "timezone": "America/Argentina/Buenos_Aires",
    "created_at": "2026-04-01T12:00:00Z"
  },
  "api_version": "v1"
}
GET/api/v1/creditsscope: read

Balance de créditos KANDIMA, último uso, total comprado/consumido, configuración de auto-recarga, y las 5 transacciones más recientes.

Request
curl https://kandima.ai/api/v1/credits \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "user_id": "user_3DaORih5ursagiFh35CZm41SMm1",
  "balance": 1250,
  "total_purchased": 5000,
  "total_spent": 3750,
  "updated_at": "2026-05-14T15:23:00Z",
  "auto_topup": {
    "enabled": true,
    "threshold": 100,
    "top_up_amount": 1000,
    "last_charged_at": "2026-05-10T08:00:00Z"
  },
  "recent_transactions": [
    {
      "kind": "consume",
      "feature": "ad_pack",
      "amount": -50,
      "balance_after": 1250,
      "created_at": "2026-05-14T15:00:00Z",
      "meta": { "campaign_id": "..." }
    }
  ],
  "api_version": "v1"
}
GET/api/v1/customersscope: read

Lista paginada de clientes (cursor-based). Filtros: source (shopify, tienda-nube, mercado-libre). Default 25, max 100. Ordenado por id desc para que items recientes aparezcan primero.

Request
curl "https://kandima.ai/api/v1/customers?limit=25&source=shopify" \
  -H "Authorization: Bearer ka_live_..."

# Paginate:
curl "https://kandima.ai/api/v1/customers?cursor=842&limit=25" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "id": 842,
      "email": "alice@example.com",
      "name": "Alice Morrow",
      "source": "shopify",
      "external_id": "shopify:kandima:alice@example.com",
      "city": "Buenos Aires",
      "country": "AR",
      "orders_count": 4,
      "revenue_total": 320.50,
      "ltv_estimate": 480.75,
      "aov": 80.13,
      "segment": "vip",
      "churn_score": 0.12,
      "last_purchase_at": "2026-05-14T10:00:00Z",
      "first_purchase_at": "2026-02-01T15:30:00Z",
      "created_at": "2026-02-01T15:30:00Z"
    }
  ],
  "pagination": {
    "limit": 25,
    "next_cursor": 818,
    "has_more": true
  },
  "api_version": "v1"
}
GET/api/v1/integrationsscope: read

Estado de cada integración OAuth conectada. Status: connected (last_sync ≤24h), stale (>24h), revoked, never_synced. Nunca devuelve tokens — solo metadata.

Request
curl https://kandima.ai/api/v1/integrations \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "provider": "shopify",
      "shop": "kandima.myshopify.com",
      "scopes": ["read_orders", "read_products"],
      "status": "connected",
      "connected_at": "2026-04-01T12:00:00Z",
      "revoked_at": null,
      "last_sync_at": "2026-05-14T15:00:00Z",
      "last_sync_minutes_ago": 23
    }
  ],
  "totals": {
    "total": 1,
    "connected": 1,
    "stale": 0,
    "revoked": 0,
    "never_synced": 0
  },
  "api_version": "v1"
}
GET/api/v1/webhooksscope: read

Lista los webhook subscriptions activos del usuario. Devuelve URL, eventos suscritos, fired/failed counts, last status.

Request
curl https://kandima.ai/api/v1/webhooks \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "id": 1,
      "url": "https://my-app.com/webhooks/kandima",
      "events": ["purchase.created", "credits.low"],
      "active": true,
      "last_fired_at": "2026-05-14T15:23:00Z",
      "last_status": 200,
      "fail_count": 0,
      "total_fired": 142,
      "total_failed": 3,
      "created_at": "2026-05-01T12:00:00Z"
    }
  ],
  "api_version": "v1"
}
POST/api/v1/webhooksscope: write

Crea un webhook subscription nuevo. Devuelve el secret una sola vez (guardalo). URL debe ser HTTPS. events default = ['*'].

Request
curl -X POST https://kandima.ai/api/v1/webhooks \
  -H "Authorization: Bearer ka_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-app.com/webhooks/kandima",
    "events": ["purchase.created", "credits.low"]
  }'
Response · 200 OK
{
  "id": 1,
  "url": "https://my-app.com/webhooks/kandima",
  "events": ["purchase.created", "credits.low"],
  "active": true,
  "created_at": "2026-05-14T15:00:00Z",
  "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "warning": "Guardá el secret ahora — no se puede recuperar después.",
  "api_version": "v1"
}
DELETE/api/v1/webhooks?id=Nscope: write

Revoca el webhook subscription. No se puede deshacer.

Request
curl -X DELETE "https://kandima.ai/api/v1/webhooks?id=1" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{ "ok": true }
GET/api/v1/insightsscope: read

Insights AI recientes generados por el cron ai-insights-generate. Filtros: status (open/resolved/dismissed), severity (low/medium/high/critical). Default 25, max 100.

Request
curl "https://kandima.ai/api/v1/insights?status=open&severity=high&limit=10" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "id": 142,
      "severity": "high",
      "category": "ads",
      "title": "ROAS cayendo en Meta últimos 7 días",
      "body": "ROAS bajó de 2.4 a 1.6...",
      "suggested_action": "Pausar adsets con ROAS < 1.5",
      "impact_estimate": "$240 USD/día",
      "status": "open",
      "computed_at": "2026-05-14T08:00:00Z",
      "resolved_at": null
    }
  ],
  "api_version": "v1"
}
POST/api/v1/trackscope: write

Inserta un evento custom en tu stream KANDIMA. Útil para first-party analytics sin depender de GA/Mixpanel. Event name max 64 chars (a-zA-Z0-9._-). Props JSON object max 8KB. Geo (country/region/city) se infiere automáticamente del IP.

Request
curl -X POST https://kandima.ai/api/v1/track \
  -H "Authorization: Bearer ka_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "event": "checkout_started",
    "props": { "plan": "pro", "amount_usd": 19 },
    "visitor_id": "v_abc123",
    "session_id": "s_xyz789",
    "url": "https://my-app.com/checkout"
  }'
Response · 200 OK
{
  "ok": true,
  "event_id": 142857,
  "api_version": "v1"
}
GET/api/v1/anomaliesscope: read

Anomalías recientes detectadas por el cron anomaly-detect. Incluye univariate (z-score per métrica) y correlated (root-cause inference cross-métrica). Filtros: severity, days (default 7, max 90).

Request
curl "https://kandima.ai/api/v1/anomalies?days=7&severity=high" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "id": 12,
      "metric": "roas",
      "observed_value": 0.8,
      "expected_value": 2.1,
      "z_score": -3.2,
      "direction": "down",
      "severity": "high",
      "detected_at": "2026-05-14T08:00:00Z",
      "inferred_cause": "Ad spend up 40% sin proporcional revenue",
      "confidence": 0.87,
      "correlated_metrics": [
        { "metric": "ad_spend", "modz": 2.4, "direction": "up" }
      ]
    }
  ],
  "window_days": 7,
  "api_version": "v1"
}
GET/api/v1/profitscope: read

Profit snapshots diarios del cron profit-snapshot. Default 30 días, max 365. Cada snapshot tiene revenue, refunds, ad_spend, COGS, fees, shipping, extras, plus net_revenue, operational_profit, final_profit, margin_pct.

Request
curl "https://kandima.ai/api/v1/profit?days=7" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "data": [
    {
      "snapshot_date": "2026-05-14",
      "gross_revenue": 1250.50,
      "refunds": 45.00,
      "ad_spend": 320.00,
      "cogs_estimate": 380.00,
      "fees_estimate": 42.50,
      "shipping_estimate": 65.00,
      "extra_expenses": 0,
      "net_revenue": 1205.50,
      "operational_profit": 398.00,
      "final_profit": 398.00,
      "margin_pct": 31.84,
      "purchase_count": 18
    }
  ],
  "totals": {
    "days_returned": 7,
    "gross_revenue": 7820.30,
    "ad_spend": 1980.00,
    "final_profit": 2340.50,
    "purchase_count": 124,
    "avg_margin_pct": 29.92
  },
  "window_days": 7,
  "api_version": "v1"
}
GET/api/v1/inventoryscope: read

Inventario por SKU con stock-on-hand, units sold (7d/30d), days-of-stock, trend y stockout estimado. Filtros: status (critical/low/ok/overstocked), limit (max 500). Powered by inventory_velocity cron.

Request
curl "https://kandima.ai/api/v1/inventory?status=critical&limit=20" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "items": [
    {
      "sku": "KND-001",
      "product_name": "Pet Brush Pro",
      "current_stock": 12,
      "units_sold_30d": 84,
      "units_sold_7d": 28,
      "avg_daily_units_30d": 2.8,
      "avg_daily_units_7d": 4.0,
      "days_of_stock": 3.0,
      "trend": "accelerating",
      "status": "critical",
      "estimated_stockout_at": "2026-05-17",
      "computed_at": "2026-05-14T10:00:00Z"
    }
  ],
  "summary": { "total": 1, "critical": 1, "low": 0, "ok": 0, "overstocked": 0 },
  "generated_at": "2026-05-14T16:30:00Z",
  "api_version": "v1"
}
GET/api/v1/reorderscope: read

Smart reorder suggestions del cron smart-reorder. Cantidades sugeridas basadas en velocity + lead time + forecast con confidence score. Filtros: status (pending/ordered/dismissed), limit (max 200).

Request
curl "https://kandima.ai/api/v1/reorder?status=pending" \
  -H "Authorization: Bearer ka_live_..."
Response · 200 OK
{
  "items": [
    {
      "id": 7,
      "inventory_item_id": 142,
      "qty_suggested": 120,
      "reason": "30d velocity 4u/día, lead time 14d, safety stock 30u",
      "confidence": 0.91,
      "forecast_days": 30,
      "computed_at": "2026-05-14T08:30:00Z",
      "status": "pending"
    }
  ],
  "generated_at": "2026-05-14T16:30:00Z",
  "api_version": "v1"
}

Webhook events catalog

Cuando suscribís un webhook, podés recibir cualquiera de estos eventos. Cada delivery viene firmado con HMAC SHA256 — verificá la firma antes de procesar.

Verificar firma · Node.js
import crypto from "node:crypto";

app.post("/webhooks/kandima", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-kandima-signature"];
  const timestamp = req.headers["x-kandima-timestamp"];
  const rawBody = req.body.toString();

  const secret = process.env.KANDIMA_WEBHOOK_SECRET; // whsec_xxxx
  const expected = crypto
    .createHmac("sha256", secret.replace(/^whsec_/, ""))
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const valid = signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!valid) return res.status(401).end();

  const { event, data } = JSON.parse(rawBody);
  // process event...
  res.status(200).end();
});
purchase.createdtrigger: Stripe webhook invoice.paid

Una invoice de Stripe se pagó (suscripción o top-up).

// data field of the delivery payload
{
  "invoice_id": "in_xxx",
  "amount": 19,
  "currency": "USD",
  "customer_email": "alice@example.com"
}
credits.lowtrigger: Cualquier feature AI consume créditos

Balance de créditos cayó debajo de 100 después de un debit.

// data field of the delivery payload
{
  "balance": 45,
  "threshold": 100,
  "last_feature": "ad_pack"
}
credits.depletedtrigger: Debit dejó balance = 0

Balance llegó a 0. Próximas features AI fallarán hasta recargar.

// data field of the delivery payload
{
  "balance": 0,
  "last_feature": "creative_analysis",
  "last_amount": 50
}
credits.rechargedtrigger: Stripe webhook checkout.session.completed (mode=payment)

Top-up exitoso (manual o auto-recarga).

// data field of the delivery payload
{
  "credits_added": 1000,
  "new_balance": 1045,
  "stripe_session": "cs_xxx",
  "source": "purchase"
}
alert.firedtrigger: Cron alerts-evaluator detecta cross

Un alert rule disparó porque un threshold se cruzó. Nivel severity puede ser low/medium/high/critical.

// data field of the delivery payload
{
  "rule_id": 42,
  "rule_name": "Daily ad spend > $100",
  "severity": "high",
  "metric": "ad_spend",
  "observed": 142.50,
  "threshold": 100,
  "comparator": ">",
  "window_hours": 24
}
anomaly.detectedtrigger: Cron anomaly-detect (z-score > umbral)

El cron de anomaly-detect encontró una desviación significativa (severity ≥ medium).

// data field of the delivery payload
{
  "metric": "roas",
  "observed": 0.8,
  "expected": 2.1,
  "z_score": -3.2,
  "direction": "down",
  "severity": "high",
  "source": "univariate"
}
integration.connectedtrigger: OAuth callback exitoso

Una integración OAuth se acaba de conectar (Shopify, Tienda Nube, etc).

// data field of the delivery payload
{
  "provider": "shopify",
  "shop": "my-store.myshopify.com"
}
integration.revokedtrigger: Webhook upstream app/uninstalled o revoke manual

Una integración fue revocada (uninstall del usuario, expiración del token, etc).

// data field of the delivery payload
{
  "provider": "tienda-nube",
  "store_id": 12345,
  "reason": "app_uninstalled"
}

Errores

Todos los errores devuelven JSON con la forma { "error": "<code>" } y un HTTP status apropiado:

401missing_authorizationNo mandaste header Authorization
401invalid_token_formatToken no empieza con ka_
401key_not_foundAPI key inválida o no existe
401key_revokedLa key fue revocada
401key_expiredLa key superó su fecha de expiración
403scope_required:writeLa key no tiene el scope requerido
429rate_limit_exceeded60 req/min superados; esperá un minuto
503no_dbDB no disponible (raro, ver /status)

Soporte

Bug, request de feature, o necesitás endpoints adicionales? Contactanos o escribí a soporte@kandima.ai.

Estado de la API en /status.