# API y MCP de Lidra SMM > Documentación técnica de la plataforma argentina de marketing en redes sociales Lidra SMM (https://lidra.com.ar). > Cubre la API REST, el endpoint compatible con paneles SMM, y el servidor MCP para asistentes de inteligencia artificial. > Última actualización: generada en cada despliegue desde el código que sirve las peticiones. ## Índice - [Introducción](#introduccion) - [Empezar en tres pasos](#empezar) - [Autenticación](#autenticacion) - [Convenciones](#convenciones) - [Límites](#limites) - [Errores](#errores) - [Referencia de la API REST](#rest) - [Servidor MCP](#mcp) - [Agente A2A](#a2a) - [Herramientas y parámetros](#herramientas) - [Endpoint compatible](#compatible) - [Recetas](#recetas) - [Buenas prácticas](#seguridad) - [Versionado](#versionado) ## Introducción Lidra SMM es una plataforma argentina de marketing en redes sociales. Esta documentación cubre las tres formas de usarla desde afuera del navegador, todas con la misma API key y los mismos permisos. - **API REST** (`/api/v1`): JSON moderno, códigos HTTP de verdad. Es la que conviene si estás escribiendo algo nuevo. - **Endpoint compatible** (`/api/v2`): habla el formato estándar de los paneles SMM. Si ya tenés software que integra un panel, apuntalo a Lidra cambiando la URL base y la key. - **Servidor MCP** (`/api/mcp`): conecta un asistente de inteligencia artificial —Claude, ChatGPT o el que uses— para que opere tu cuenta hablándole en castellano. Las tres exponen las mismas 24 operaciones. Todo lo que podés hacer desde la web, podés hacerlo desde acá. > **Ojo.** Para usar cualquiera de las tres tenés que activar el **Modo desarrollador** en Mi cuenta. Apagarlo corta la API y el MCP al instante, sin borrar tus keys. ## Empezar en tres pasos 1. Entrá a **Mi cuenta** y activá el **Modo desarrollador**. 2. Andá a **Desarrollador** y creá una API key. Se muestra una sola vez: copiala. 3. Probala. Si responde, ya está. ```bash curl https://lidra.com.ar/api/v1/status \ -H "Authorization: Bearer lidra_sk_TU_API_KEY" ``` ```json { "ok": true, "apiVersion": "v1", "surface": "rest", "scopes": ["catalog:read", "orders:read", "orders:write", "..."], "serverTime": "2026-07-09T14:32:10.000Z" } ``` Un flujo completo, de un link a un pedido: analizás el link, cotizás, y recién ahí comprás. ```bash # 1. ¿Qué se le puede comprar a este link? curl "https://lidra.com.ar/api/v1/links/services?url=https://instagram.com/p/ABC123" \ -H "Authorization: Bearer $LIDRA_KEY" # 2. ¿Cuánto sale? (no cobra nada) curl -X POST https://lidra.com.ar/api/v1/quotes \ -H "Authorization: Bearer $LIDRA_KEY" \ -H "Content-Type: application/json" \ -d '{"serviceId":"svc_a1b2c3d4e5f6a7b8","quantity":1000}' # 3. Comprar (esto SÍ cobra tu saldo) curl -X POST https://lidra.com.ar/api/v1/orders \ -H "Authorization: Bearer $LIDRA_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: mi-pedido-0001" \ -d '{"serviceId":"svc_a1b2c3d4e5f6a7b8","link":"https://instagram.com/p/ABC123","quantity":1000}' ``` ## Autenticación Toda petición lleva tu API key en el header `Authorization`. En el endpoint compatible va como campo `key` del cuerpo, porque así lo define ese formato. ```http Authorization: Bearer lidra_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` La key **nunca** se lee de una cookie. Eso significa que un sitio hostil no puede hacer peticiones a la API en tu nombre aunque tengas la sesión de Lidra abierta. > **Ojo.** Tratá la key como una contraseña. No la pongas en código de navegador, ni en un repositorio, ni en una app móvil: cualquiera que la vea puede gastar tu saldo. Usala desde tu servidor. **Formato.** `lidra_sk_` seguido de 32 caracteres. El prefijo sirve para reconocerla de un vistazo y para que los detectores de secretos la marquen si se filtra. **Se muestra una sola vez.** Al crearla, y al rotarla. Después no la tiene nadie: en nuestra base solo queda un hash SHA-256, que no se puede revertir. Ni el equipo de Lidra puede leer tu key. Si la perdés, rotala. **Rotación.** Rotar una key le cambia el secreto en el lugar: te damos uno nuevo y el anterior deja de funcionar en el acto. El nombre, los permisos y el identificador de la key se mantienen. Rotá cuando sospeches una filtración, cuando se vaya alguien del equipo, o cada tanto por higiene. **Vencimiento.** Al crear la key elegís 30, 90 o 365 días, o ninguno. Una key sin vencimiento es una key que nunca se rota: si la integración va a durar, ponele fecha. **Revocar y eliminar.** Revocar la mata para siempre. Eliminar borra además su registro. Podés tener hasta 10 keys activas a la vez; una por integración es una buena idea, porque te deja revocar solo la comprometida. **Permisos (scopes).** Cada key lleva la lista de lo que puede hacer. Una petición sin el permiso necesario devuelve `403 insufficient_scope`. Dale a cada key el mínimo que necesite: si tu bot solo mira pedidos, no le des `orders:write`. | Permiso | Qué habilita | Detalle | | --- | --- | --- | | `catalog:read` | Ver el catálogo | Buscar servicios, analizar links y cotizar pedidos. | | `orders:read` | Ver pedidos | Listar tus pedidos y consultar su avance. | | `orders:write` | Crear y modificar pedidos | Hacer pedidos nuevos (gasta tu saldo), cancelar y pedir reposición. | | `wallet:read` | Ver la billetera | Consultar tu saldo y tus movimientos. | | `wallet:topup` | Generar recargas | Crear un link de pago de Mercado Pago para cargar saldo. | | `clients:read` | Ver clientes | Listar tus clientes y carpetas del CRM. | | `clients:write` | Crear clientes | Agregar clientes y carpetas al CRM. | | `tickets:read` | Ver soporte | Listar tus consultas de soporte y sus respuestas. | | `tickets:write` | Escribir a soporte | Abrir consultas nuevas y responder las existentes. | | `profile:read` | Ver tu perfil | Consultar tu email, nombre y saldo. | > **Ojo.** No existe ningún permiso de administración. La API y el MCP solo pueden tocar **tus** datos: tus pedidos, tu saldo, tus clientes. Nada de precios, catálogo interno ni cuentas ajenas. ## Convenciones **Dinero.** Todos los montos son **enteros en centavos de pesos argentinos**. `208000` son $2.080,00. Nunca hay decimales ni números en coma flotante, así que no hay errores de redondeo. Los campos que llevan plata terminan en `ArsCents`. **Excepción.** El endpoint compatible (`/api/v2`) usa pesos como texto decimal (`"2080.0000"`), porque es lo que ese formato define y lo que sus clientes esperan. **Fechas.** Siempre ISO 8601 en UTC: `2026-07-09T14:32:10.000Z`. **Identificadores.** Los servicios usan un id opaco que empieza con `svc_`. Los pedidos, clientes y consultas usan UUID. Son estables: guardalos. **Paginación.** Los listados aceptan `limit` (hasta 100) y `offset`, y devuelven `total` y `hasMore`. **Idempotencia.** `POST /api/v1/orders` acepta el header `Idempotency-Key`. Si reintentás con la misma clave, te devolvemos el pedido original en vez de crear otro y cobrarte dos veces. Usá una clave distinta por pedido y guardala antes de llamar. Reintentar con la misma clave y un cuerpo distinto devuelve el pedido original: la clave manda. **Estados de pedido.** Un pedido nace en `pending` y avanza solo. No hace falta reintentar nada: si el despacho falla, lo reintentamos por vos. | Estado | En pantalla | Qué significa | | --- | --- | --- | | `pending` | Pendiente | Cobrado y en cola. Todavía no empezó a entregarse. | | `processing` | En progreso | Entregándose. | | `completed` | Completado | Entregado por completo. | | `partial` | Entrega parcial | Se entregó una parte. La diferencia se reintegró al saldo. | | `canceled` | Cancelado | Cancelado. El saldo se reintegró. | | `refunded` | Reembolsado | Reembolsado por completo. | | `failed` | Fallido | No se pudo procesar. El saldo se reintegró. | **Cómo seguir un pedido.** Consultá `GET /api/v1/orders/{orderId}`. Si seguís muchos, usá `POST /api/v1/orders/status` con hasta 100 ids en una sola petición: es lo que corresponde y no te come el límite. Consultar cada 30 segundos mientras haya pedidos activos alcanza y sobra. ## Límites | Qué | Límite | | --- | --- | | Peticiones por API key | 240 por minuto | | Creación de pedidos | 30 por minuto | | Pedidos por consulta de estado en lote | 100 | | Resultados por página | 100 | | API keys activas por cuenta | 10 | | Recarga mínima | 50.000 centavos ($500) | | Recarga máxima | 100.000.000 centavos ($1.000.000) | Cada respuesta trae `X-RateLimit-Limit`, `X-RateLimit-Remaining` y `X-RateLimit-Reset`. Si te pasás, devolvemos `429` con `Retry-After` en segundos: esperá eso y reintentá. ## Errores La API REST usa códigos HTTP y siempre devuelve el mismo cuerpo: ```json { "error": { "code": "insufficient_funds", "message": "Saldo insuficiente. Cargá créditos antes de hacer el pedido.", "docs": "https://lidra.com.ar/desarrolladores#errores" } } ``` | Código | HTTP | Qué pasó | | --- | --- | --- | | `unauthorized` | 401 | No mandaste la API key. | | `invalid_key` | 401 | La key no existe o está mal escrita. | | `key_revoked` | 401 | La key fue revocada. | | `key_expired` | 401 | La key venció. | | `developer_mode_disabled` | 403 | El modo desarrollador está apagado. Activalo en Mi cuenta. | | `insufficient_scope` | 403 | La key no tiene el permiso que esa operación necesita. | | `rate_limited` | 429 | Demasiadas peticiones. Mirá `Retry-After`. | | `validation_error` | 400 | Un parámetro falta o está mal. El detalle dice cuál. | | `quantity_out_of_range` | 400 | La cantidad está fuera del mínimo o el máximo del servicio. | | `not_found` | 404 | El recurso no existe, o no es tuyo. | | `feature_disabled` | 404 | Esa función no está habilitada. | | `insufficient_funds` | 402 | No te alcanza el saldo. Usá `create_topup`. | | `service_unavailable` | 409 | El servicio no se puede comprar ahora mismo. | | `order_not_cancelable` | 409 | El pedido ya arrancó a entregarse. | | `refill_not_available` | 409 | Ese pedido no admite reposición, o ya la pediste. | | `temporarily_unavailable` | 503 | Problema temporal. Reintentá en unos minutos. | | `internal_error` | 500 | Error nuestro. Si se repite, escribinos. | > **Ojo.** `not_found` también aparece cuando pedís algo que existe pero es de otra cuenta. Es a propósito: no confirmamos la existencia de recursos ajenos. ## Referencia de la API REST Base: `https://lidra.com.ar/api/v1`. Todas las peticiones necesitan el header `Authorization`. | Endpoint | Qué hace | Permiso | Tool MCP equivalente | | --- | --- | --- | --- | | `POST /api/v1/links/detect` | Analizar un link | `catalog:read` | `detect_link` | | `GET /api/v1/links/services` | Servicios compatibles con un link | `catalog:read` | `services_for_link` | | `GET /api/v1/services` | Buscar servicios | `catalog:read` | `search_services` | | `GET /api/v1/services/{serviceId}` | Ver un servicio | `catalog:read` | `get_service` | | `POST /api/v1/quotes` | Cotizar un pedido | `catalog:read` | `quote_order` | | `POST /api/v1/orders` | Crear un pedido | `orders:write` | `create_order` | | `GET /api/v1/orders` | Listar pedidos | `orders:read` | `list_orders` | | `GET /api/v1/orders/{orderId}` | Ver un pedido | `orders:read` | `get_order` | | `POST /api/v1/orders/status` | Estado de varios pedidos | `orders:read` | `get_orders_status` | | `POST /api/v1/orders/{orderId}/cancel` | Cancelar un pedido | `orders:write` | `cancel_order` | | `POST /api/v1/orders/{orderId}/refill` | Pedir reposición | `orders:write` | `request_refill` | | `GET /api/v1/orders/{orderId}/refill` | Estado de la reposición | `orders:read` | `get_refill_status` | | `GET /api/v1/wallet` | Ver el saldo | `wallet:read` | `get_balance` | | `GET /api/v1/wallet/transactions` | Listar movimientos | `wallet:read` | `list_transactions` | | `POST /api/v1/wallet/topups` | Generar una recarga | `wallet:topup` | `create_topup` | | `GET /api/v1/clients` | Listar clientes | `clients:read` | `list_clients` | | `POST /api/v1/clients` | Crear un cliente | `clients:write` | `create_client` | | `GET /api/v1/folders` | Listar carpetas | `clients:read` | `list_folders` | | `POST /api/v1/folders` | Crear una carpeta | `clients:write` | `create_folder` | | `GET /api/v1/tickets` | Listar consultas de soporte | `tickets:read` | `list_tickets` | | `POST /api/v1/tickets` | Abrir una consulta de soporte | `tickets:write` | `create_ticket` | | `POST /api/v1/tickets/{ticketId}/replies` | Responder una consulta | `tickets:write` | `reply_ticket` | | `GET /api/v1/me` | Ver tu perfil | `profile:read` | `get_profile` | | `GET /api/v1/status` | Estado de la API | — | `get_api_status` | Los parámetros de cada operación están en la tabla de herramientas MCP más abajo: son exactamente los mismos. En `GET` van en el query string, en `POST` en el cuerpo JSON. El esquema completo, con tipos y validaciones, está publicado en formato OpenAPI 3.1: ```bash curl https://lidra.com.ar/api/openapi.json ``` ## Servidor MCP MCP (Model Context Protocol) es el estándar que usan los asistentes de inteligencia artificial para conectarse a servicios externos. Conectando Lidra por MCP, tu asistente puede buscar servicios, cotizar, ver tu saldo y hacer pedidos, hablándole en castellano. No hay nada que instalar: el servidor vive en `https://lidra.com.ar/api/mcp` y se autentica con tu misma API key. **Claude Code**, una línea en la terminal: ```bash claude mcp add --transport http lidra https://lidra.com.ar/api/mcp \ --header "Authorization: Bearer lidra_sk_TU_API_KEY" ``` **Claude Desktop** y otros clientes, en el archivo de configuración: ```json { "mcpServers": { "lidra": { "type": "http", "url": "https://lidra.com.ar/api/mcp", "headers": { "Authorization": "Bearer lidra_sk_TU_API_KEY" } } } } ``` **Detalles del transporte**, por si estás escribiendo un cliente: Streamable HTTP sin estado. `POST` con un mensaje JSON-RPC 2.0 y respuesta `application/json` (no abrimos stream SSE). Las notificaciones se contestan con `202`. `GET` y `DELETE` devuelven `405`. No emitimos `Mcp-Session-Id`. Versiones de protocolo soportadas: `2025-11-25`, `2025-06-18`, `2025-03-26`. Métodos: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`, `prompts/list`, `prompts/get`. Cada herramienta devuelve un resumen en castellano en `content` y el JSON completo en `structuredContent`. Un error de negocio (saldo insuficiente, pedido no cancelable) vuelve como `isError: true` con la explicación, no como un error de protocolo. **Recursos**: `lidra://catalogo/taxonomia` (todos los valores válidos) y `lidra://cuenta/permisos` (qué puede hacer tu key). **Prompts**: `comprar`, `revisar_pedidos` y `diagnosticar_pedido`, que guían al asistente por el flujo correcto. > **Ojo.** El asistente solo puede hacer lo que permita la key que le diste. Si querés que consulte pero no compre, creá una key de solo lectura. `create_order` gasta plata real: el prompt `comprar` está escrito para que el asistente te pida confirmación antes. ## Agente A2A A2A (Agent2Agent) es el otro lado de la moneda del MCP: en MCP tu asistente usa las herramientas de Lidra; en A2A, **tu agente le habla al agente de Lidra** y este le contesta. El agente vive en `https://lidra.com.ar/api/a2a` y su tarjeta —qué sabe hacer y cómo hablarle— en `https://lidra.com.ar/.well-known/agent-card.json`. Se autentica con la misma API key. Hace tres cosas y nada más. Si le mandás un **link**, te dice qué se le puede comprar y a cuánto. Si le mandás una **habilidad con sus datos**, la ejecuta. Si no le mandás ninguna de las dos, te dice qué sabe hacer. **No hay un modelo de lenguaje adentro**: es determinístico, y por eso no le pidas que interprete una consigna libre. Pasarle un link (lo más común): ```bash curl -X POST https://lidra.com.ar/api/a2a \ -H "Authorization: Bearer $LIDRA_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "message/send", "params": { "message": { "kind": "message", "messageId": "m1", "role": "user", "parts": [{ "kind": "text", "text": "https://instagram.com/p/ABC123" }] } } }' ``` Ejecutar una habilidad concreta, con una parte de datos: ```json { "kind": "message", "messageId": "m2", "role": "user", "parts": [{ "kind": "data", "data": { "skill": "quote_order", "input": { "serviceId": "svc_a1b2c3d4e5f6a7b8", "quantity": 1000 } } }] } ``` La respuesta es siempre un `Message` del agente con dos partes: una de texto con el resumen en castellano, y una de datos con el JSON completo. **No hay tareas de larga duración**: `tasks/get`, `message/stream` y los avisos por webhook devuelven el error que corresponde en vez de dejarte esperando. La tarjeta lo declara en `capabilities`. Las habilidades son las mismas 24 operaciones de la tabla de abajo, con los mismos permisos y los mismos límites. Un error de negocio (saldo insuficiente, permiso faltante) vuelve dentro del mensaje, no como error de protocolo. ## Herramientas y parámetros Las 24 operaciones, con sus parámetros. Los marcados con `*` son obligatorios. Valen igual para la API REST: son los mismos nombres. | Nombre | Qué hace | Parámetros | Permiso | | --- | --- | --- | --- | | `detect_link` | Lee un link de red social y devuelve de qué plataforma es, qué tipo de contenido, y qué métricas se le pueden comprar. Primer paso natural antes de buscar servicios. | `url`* | `catalog:read` | | `services_for_link` | Dado un link, devuelve todos los servicios que se le pueden aplicar, con el precio del día en pesos. Es la forma más rápida de pasar de un link a algo comprable. | `url`* | `catalog:read` | | `search_services` | Busca en el catálogo por plataforma, métrica, tipo de contenido o nombre. Devuelve el precio final en centavos de ARS por cada 1000 unidades. | `platform`, `metric`, `contentType`, `query`, `limit`, `offset` | `catalog:read` | | `get_service` | Devuelve el detalle de un servicio: precio, mínimo, máximo y si admite reposición o entrega gradual. | `serviceId`* | `catalog:read` | | `quote_order` | Calcula cuánto costaría un pedido sin crearlo ni cobrar nada. Usalo siempre antes de `create_order` para confirmarle el precio a la persona. | `serviceId`*, `quantity`*, `runs`, `intervalMinutes` | `catalog:read` | | `create_order` | Crea un pedido y COBRA el saldo de la billetera al instante. Confirmá el precio con `quote_order` antes de llamar a esto. El pedido vuelve en estado `pending`; el avance se consulta con `get_order`. | `serviceId`*, `link`*, `quantity`*, `runs`, `intervalMinutes`, `comments`, `clientId`, `resellPriceArsCents`, `idempotencyKey` | `orders:write` | | `list_orders` | Devuelve tus pedidos, con filtros por estado, plataforma o cliente. | `status`, `platform`, `clientId`, `limit`, `offset` | `orders:read` | | `get_order` | Devuelve un pedido con su estado, lo entregado y lo que falta. | `orderId`* | `orders:read` | | `get_orders_status` | Consulta hasta 100 pedidos de una sola vez. Es la forma correcta de seguir el avance de muchos pedidos sin gastar el límite de peticiones. | `orderIds`* | `orders:read` | | `cancel_order` | Cancela un pedido que todavía no empezó a entregarse y reintegra el saldo. Si la entrega ya arrancó, no se puede: hay que abrir una consulta de soporte. | `orderId`* | `orders:write` | | `request_refill` | Pide la reposición de un pedido completado, si el servicio la admite (por ejemplo, seguidores que se cayeron). Se puede pedir una sola vez por pedido. | `orderId`* | `orders:write` | | `get_refill_status` | Devuelve si la reposición de un pedido está pedida, en curso, completada o rechazada. | `orderId`* | `orders:read` | | `get_balance` | Devuelve el saldo disponible en la billetera, en centavos de ARS. | — | `wallet:read` | | `list_transactions` | Devuelve los movimientos de la billetera: recargas, cobros de pedidos, reintegros y ajustes. | `limit` | `wallet:read` | | `create_topup` | Crea un link de pago de Mercado Pago para cargar saldo. Devuelve la URL; el saldo se acredita recién cuando el pago se aprueba. | `amountArsCents`* | `wallet:topup` | | `list_clients` | Devuelve los clientes de tu CRM, con cuántos pedidos hizo cada uno y cuánto gastó. | — | `clients:read` | | `create_client` | Agrega un cliente a tu CRM para imputarle pedidos. | `name`*, `folderId`, `handle`, `notes` | `clients:write` | | `list_folders` | Devuelve las carpetas con las que organizás tus clientes. | — | `clients:read` | | `create_folder` | Crea una carpeta para agrupar clientes. | `name`* | `clients:write` | | `list_tickets` | Devuelve tus consultas de soporte con todos sus mensajes. | — | `tickets:read` | | `create_ticket` | Abre una consulta de soporte, opcionalmente asociada a un pedido. | `subject`*, `body`*, `orderId` | `tickets:write` | | `reply_ticket` | Agrega un mensaje tuyo a una consulta existente. Si estaba cerrada, se reabre. | `ticketId`*, `body`* | `tickets:write` | | `get_profile` | Devuelve tu email, tu nombre y tu saldo. | — | `profile:read` | | `get_api_status` | Confirma que la API key funciona y devuelve qué permisos tiene. No necesita ningún permiso. | — | — | ## Endpoint compatible `POST https://lidra.com.ar/api/v2` habla el formato estándar de la industria de paneles SMM. Si ya tenés software que integra un panel, apuntalo acá: solo cambia la URL base y la key. > **Ojo.** Ese formato responde **HTTP 200 con `{"error": "..."}`** cuando algo falla, en vez de un código de error. Lo respetamos para no romper los clientes existentes. Si estás escribiendo algo nuevo, usá la API REST: te va a dar mejores errores. Los parámetros van como `application/x-www-form-urlencoded` (también aceptamos JSON), con `key` y `action`. ```bash curl -X POST https://lidra.com.ar/api/v2 \ -d "key=lidra_sk_TU_API_KEY" \ -d "action=balance" # {"balance":"12500.0000","currency":"ARS"} ``` | `action` | Parámetros | Respuesta | | --- | --- | --- | | `services` | — | Lista completa de servicios. | | `add` | `service`, `link`, `quantity`, y opcionales `runs`, `interval`, `comments` | `{ "order": "" }` | | `status` | `order` (uno) u `orders` (hasta 100, separados por coma) | `{ charge, start_count, status, remains, currency }`, o un objeto por id. | | `balance` | — | `{ "balance": "1234.5600", "currency": "ARS" }` | | `refill` | `order` u `orders` | `{ "refill": "" }` | | `refill_status` | `refill` (el id del pedido) | `{ "status": "..." }` | | `cancel` | `order` u `orders` | Un objeto por pedido con `cancel`. | Los montos van en pesos como texto decimal, con `currency: "ARS"`. Los estados son `Pending`, `In progress`, `Completed`, `Partial`, `Canceled` y `Refunded`. ## Recetas **Comprar sin sorpresas.** Cotizá antes, y usá una clave de idempotencia. ```javascript const base = "https://lidra.com.ar/api/v1"; const headers = { Authorization: `Bearer ${process.env.LIDRA_KEY}`, "Content-Type": "application/json", }; // 1. Cotizar. No cobra nada. const quote = await fetch(`${base}/quotes`, { method: "POST", headers, body: JSON.stringify({ serviceId, quantity: 1000 }), }).then((r) => r.json()); // 2. ¿Alcanza el saldo? const { balanceArsCents } = await fetch(`${base}/wallet`, { headers }).then((r) => r.json()); if (balanceArsCents < quote.totalArsCents) { const topup = await fetch(`${base}/wallet/topups`, { method: "POST", headers, body: JSON.stringify({ amountArsCents: quote.totalArsCents - balanceArsCents }), }).then((r) => r.json()); throw new Error(`Cargá saldo acá: ${topup.checkoutUrl}`); } // 3. Comprar. La clave de idempotencia hace que un reintento no duplique el cobro. const order = await fetch(`${base}/orders`, { method: "POST", headers: { ...headers, "Idempotency-Key": `pedido-${miId}` }, body: JSON.stringify({ serviceId, link, quantity: 1000 }), }).then((r) => r.json()); ``` **Seguir muchos pedidos.** Una sola petición para hasta 100. ```javascript const { orders } = await fetch(`${base}/orders/status`, { method: "POST", headers, body: JSON.stringify({ orderIds: misIds }), }).then((r) => r.json()); const activos = orders.filter((o) => o.status === "pending" || o.status === "processing"); // Volvé a consultar en 30 segundos mientras queden activos. ``` **Reintentar bien.** Ante `429`, esperá lo que diga `Retry-After`. Ante `5xx`, reintentá con espera creciente. Ante `4xx`, no reintentes: arreglá la petición. ```javascript async function conReintento(fn, intentos = 4) { for (let i = 0; i < intentos; i++) { const res = await fn(); if (res.status === 429) { const esperar = Number(res.headers.get("retry-after") ?? 1); await new Promise((r) => setTimeout(r, esperar * 1000)); continue; } if (res.status >= 500 && i < intentos - 1) { await new Promise((r) => setTimeout(r, 2 ** i * 1000)); continue; } return res; } throw new Error("Se agotaron los reintentos."); } ``` ## Buenas prácticas - Una key por integración. Si una se filtra, revocás esa sola. - El mínimo de permisos. Si tu bot solo consulta, no le des `orders:write`. - La key vive en el servidor. Nunca en el navegador, en una app móvil ni en un repositorio. - Ponele vencimiento y rotala. Rotar es un botón y no te cambia el nombre ni los permisos. - Guardá la clave de idempotencia **antes** de llamar a `create_order`, no después. - Si algo se puso raro, apagá el **Modo desarrollador**: corta todo al instante y no perdés nada. ## Versionado `/api/v1` es la versión estable. Vamos a agregar campos y operaciones sin avisar, así que tu código tiene que **ignorar los campos que no conozca**. Si alguna vez tenemos que romper algo, va a ser en una ruta nueva (`/api/v2/...` no cuenta: eso es el endpoint compatible, que es otra cosa y no va a cambiar). Para el MCP, la negociación de versión del protocolo la hace el cliente en `initialize`. Soportamos `2025-11-25`, `2025-06-18`, `2025-03-26`. ¿Dudas o algo roto? Escribinos a **soporte@lidra.com.ar**, o abrí una consulta desde la app (o con `create_ticket`, que para eso está).