API de RepuestoVIPVersión 1.0 · JSON · openapi.json

Cómo entrar

Cada negocio crea sus llaves en el panel, en Ajustes › API y portal. Una llave puede ser de lectura (solo GET) o de escritura (también POST y PUT). Va en la cabecera de cada llamada:

curl http://repuestovip.com/api/v1/productos?q=filtro \
  -H "Authorization: Bearer rv_TU_LLAVE"

Las respuestas traen data; las listas además traen pagina, paginas y total. Los errores traen error con el texto y el código HTTP que corresponde: 401 llave inválida, 403 sin alcance o sin módulo, 404 no existe, 422 datos inválidos (con errors por campo). Límite: 120 llamadas por minuto por llave.

Endpoints

GET/api/v1/yolectura

Quién soy: el negocio al que pertenece la llave.

Respuesta
{
    "data": {
        "negocio": "Repuestos El Volante",
        "rnc": "130123456",
        "pais": "DO",
        "moneda": "DOP",
        "impuesto": {
            "nombre": "ITBIS",
            "pct": 18
        },
        "llave": "Tienda en línea"
    }
}
GET/api/v1/productoslectura

Catálogo con precio y existencia por sucursal.

qBusca por nombre, SKU o código de barras
por_paginaHasta 100 (50 por defecto)
pageNúmero de página
Respuesta
{
    "data": [
        {
            "sku": "FIL-001",
            "barras": "7501234567890",
            "nombre": "Filtro de aceite Toyota",
            "categoria": "Filtros",
            "precio": 450,
            "impuesto_pct": 18,
            "maneja_stock": true,
            "existencia": 21,
            "por_sucursal": {
                "1": 21
            }
        }
    ],
    "pagina": 1,
    "paginas": 3,
    "total": 120
}
GET/api/v1/productos/{sku}lectura

Un producto por SKU o código de barras.

Respuesta
{
    "data": {
        "sku": "FIL-001",
        "nombre": "Filtro de aceite Toyota",
        "precio": 450,
        "existencia": 21
    }
}
PUT/api/v1/productos/{sku}escritura

Cambia precio, precio mayorista, nombre o si está activo. La existencia no se toca por aquí: eso lo hacen las compras y las ventas.

Cuerpo (JSON)
{
    "precio": 475,
    "precio_mayorista": 430,
    "activo": true
}
Respuesta
{
    "data": {
        "sku": "FIL-001",
        "precio": 475
    }
}
GET/api/v1/clienteslectura

Clientes, con el enlace de su portal.

qNombre, teléfono, documento o correo
por_paginaHasta 100
Respuesta
{
    "data": [
        {
            "id": 12,
            "nombre": "Carlos Rodríguez",
            "documento": "048-0000001-1",
            "telefono": "8095550101",
            "whatsapp": "8095550101",
            "email": null,
            "portal": "https://tu-dominio/mi/abc…"
        }
    ],
    "pagina": 1,
    "paginas": 3,
    "total": 120
}
GET/api/v1/clientes/{id}lectura

Un cliente con sus vehículos.

Respuesta
{
    "data": {
        "id": 12,
        "nombre": "Carlos Rodríguez",
        "vehiculos": [
            {
                "id": 3,
                "descripcion": "Toyota Corolla 2018",
                "placa": "A123456",
                "kilometraje": 145230
            }
        ]
    }
}
POST/api/v1/clientesescritura

Crea un cliente. Si el teléfono o el documento ya existen, devuelve ese cliente en vez de duplicarlo.

Cuerpo (JSON)
{
    "nombre": "María Gómez",
    "telefono": "8095550202",
    "whatsapp": "8095550202",
    "email": "maria@ejemplo.com",
    "documento_tipo": "cedula",
    "documento": "001-0000002-2"
}
Respuesta
{
    "data": {
        "id": 40,
        "nombre": "María Gómez",
        "portal": "https://tu-dominio/mi/…"
    },
    "creado": true
}
GET/api/v1/facturaslectura

Facturas de un período.

desdeAAAA-MM-DD (inicio de mes por defecto)
hastaAAAA-MM-DD (hoy)
estadopendiente, parcial, pagada o anulada
por_paginaHasta 100
Respuesta
{
    "data": [
        {
            "numero": "FAC-000120",
            "ncf": "B0200000120",
            "fecha": "2026-09-22",
            "cliente": "Carlos Rodríguez",
            "condicion": "contado",
            "estado": "pagada",
            "subtotal": 900,
            "impuesto": 162,
            "total": 1062,
            "pagado": 1062,
            "balance": 0
        }
    ],
    "pagina": 1,
    "paginas": 3,
    "total": 120
}
GET/api/v1/facturas/{numero}lectura

Una factura con sus líneas. También por NCF.

Respuesta
{
    "data": {
        "numero": "FAC-000120",
        "total": 1062,
        "lineas": [
            {
                "tipo": "producto",
                "descripcion": "Filtro de aceite Toyota",
                "cantidad": 2,
                "precio": 450,
                "descuento": 0,
                "total": 1062
            }
        ]
    }
}
POST/api/v1/facturasescritura

Emite una factura de mostrador (por ejemplo, una venta de la tienda en línea). Sale del almacén de la sucursal principal y queda pendiente de cobro a nombre de cliente_id (obligatorio); se cobra desde el panel. Un precio por debajo del mínimo del producto se rechaza.

Cuerpo (JSON)
{
    "cliente_id": 12,
    "condicion": "contado",
    "notas": "Pedido web #5521",
    "lineas": [
        {
            "sku": "FIL-001",
            "cantidad": 2
        },
        {
            "sku": "ACE-010",
            "cantidad": 1,
            "precio": 1200
        }
    ]
}
Respuesta
{
    "data": {
        "numero": "FAC-000121",
        "total": 2478,
        "balance": 2478,
        "estado": "pendiente"
    }
}
GET/api/v1/ordenes/{numero}lectura

Una orden de trabajo con estado, líneas e historial.

Respuesta
{
    "data": {
        "numero": "OT-000001",
        "estado": "en_reparacion",
        "estado_texto": "En reparación",
        "cliente": "Carlos Rodríguez",
        "vehiculo": {
            "descripcion": "Toyota Corolla 2018",
            "placa": "A123456"
        },
        "fecha_promesa": "2026-09-24",
        "total": 6600,
        "lineas": [],
        "historial": []
    }
}
GET/api/v1/cotizaciones/{numero}lectura

Una cotización con sus líneas.

Respuesta
{
    "data": {
        "numero": "COT-000012",
        "estado": "pendiente",
        "total": 14000,
        "vence": "2026-10-07",
        "lineas": []
    }
}
POST/api/v1/citasescritura

Agenda una cita (por ejemplo, desde la web del negocio). Si el teléfono ya es de un cliente, la cita queda a su nombre.

Cuerpo (JSON)
{
    "nombre": "Pedro Web",
    "telefono": "8095550000",
    "vehiculo": "Hyundai Accent 2019",
    "motivo": "Cambio de aceite",
    "fecha": "2026-09-25",
    "hora": "10:00",
    "notas": "Viene con prisa"
}
Respuesta
{
    "data": {
        "numero": "AG-000015",
        "fecha": "2026-09-25",
        "hora": "10:00 am",
        "estado": "programada"
    }
}

Webhooks

En el panel se registran direcciones a las que se les avisa cuando pasa algo. A cada una le llega un POST con JSON y estas cabeceras: X-RepuestoVIP-Evento con el nombre del evento y X-RepuestoVIP-Firma con el HMAC-SHA256 del cuerpo usando el secreto del webhook. Respondan 2xx en menos de 6 segundos; no hay reintentos, el panel muestra el último resultado.

factura.emitidaFactura emitidaCuando nace una factura, de mostrador o de una orden
orden.estadoOrden cambió de estadoCada paso de una orden de trabajo
cotizacion.decididaCotización aprobada o rechazadaPor el cliente en su portal o por el taller
cita.creadaCita agendadaDesde el panel, el portal del cliente o la API
Cuerpo que llega
{
    "evento": "factura.emitida",
    "negocio": 7,
    "fecha": "2026-09-22T14:05:11-04:00",
    "datos": {
        "numero": "FAC-000121",
        "cliente": "Carlos Rodríguez",
        "total": 2478,
        "condicion": "contado",
        "origen": "pos"
    }
}
Verificar la firma (PHP)
$cuerpo = file_get_contents('php://input');
$firma  = $_SERVER['HTTP_X_REPUESTOVIP_FIRMA'] ?? '';
if (! hash_equals(hash_hmac('sha256', $cuerpo, $secreto), $firma)) {
    http_response_code(401); exit;
}