{
    "openapi": "3.0.3",
    "info": {
        "title": "RepuestoVIP API",
        "version": "1.0",
        "description": "La API del negocio. Se entra con una llave (Bearer) creada en el panel, en Ajustes › API y portal."
    },
    "servers": [
        {
            "url": "http://repuestovip.com/api"
        }
    ],
    "components": {
        "securitySchemes": {
            "llave": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "rv_…"
            }
        }
    },
    "paths": {
        "/v1/yo": {
            "get": {
                "summary": "Quién soy: el negocio al que pertenece la llave.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "negocio": "Repuestos El Volante",
                                        "rnc": "130123456",
                                        "pais": "DO",
                                        "moneda": "DOP",
                                        "impuesto": {
                                            "nombre": "ITBIS",
                                            "pct": 18
                                        },
                                        "llave": "Tienda en línea"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                }
            }
        },
        "/v1/productos": {
            "get": {
                "summary": "Catálogo con precio y existencia por sucursal.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "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
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Busca por nombre, SKU o código de barras",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Hasta 100 (50 por defecto)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "description": "Número de página",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/v1/productos/{sku}": {
            "get": {
                "summary": "Un producto por SKU o código de barras.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "sku": "FIL-001",
                                        "nombre": "Filtro de aceite Toyota",
                                        "precio": 450,
                                        "existencia": 21
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "sku",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "put": {
                "summary": "Cambia precio, precio mayorista, nombre o si está activo. La existencia no se toca por aquí: eso lo hacen las compras y las ventas.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "sku": "FIL-001",
                                        "precio": 475
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    },
                    "422": {
                        "description": "Datos incompletos o inválidos"
                    }
                },
                "parameters": [
                    {
                        "name": "sku",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "precio": 475,
                                "precio_mayorista": 430,
                                "activo": true
                            }
                        }
                    }
                }
            }
        },
        "/v1/clientes": {
            "get": {
                "summary": "Clientes, con el enlace de su portal.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "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
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Nombre, teléfono, documento o correo",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Hasta 100",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "summary": "Crea un cliente. Si el teléfono o el documento ya existen, devuelve ese cliente en vez de duplicarlo.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 40,
                                        "nombre": "María Gómez",
                                        "portal": "https://tu-dominio/mi/…"
                                    },
                                    "creado": true
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    },
                    "422": {
                        "description": "Datos incompletos o inválidos"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "nombre": "María Gómez",
                                "telefono": "8095550202",
                                "whatsapp": "8095550202",
                                "email": "maria@ejemplo.com",
                                "documento_tipo": "cedula",
                                "documento": "001-0000002-2"
                            }
                        }
                    }
                }
            }
        },
        "/v1/clientes/{id}": {
            "get": {
                "summary": "Un cliente con sus vehículos.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 12,
                                        "nombre": "Carlos Rodríguez",
                                        "vehiculos": [
                                            {
                                                "id": 3,
                                                "descripcion": "Toyota Corolla 2018",
                                                "placa": "A123456",
                                                "kilometraje": 145230
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/v1/facturas": {
            "get": {
                "summary": "Facturas de un período.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "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
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "desde",
                        "in": "query",
                        "required": false,
                        "description": "AAAA-MM-DD (inicio de mes por defecto)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "hasta",
                        "in": "query",
                        "required": false,
                        "description": "AAAA-MM-DD (hoy)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "estado",
                        "in": "query",
                        "required": false,
                        "description": "pendiente, parcial, pagada o anulada",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Hasta 100",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            },
            "post": {
                "summary": "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.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "numero": "FAC-000121",
                                        "total": 2478,
                                        "balance": 2478,
                                        "estado": "pendiente"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    },
                    "422": {
                        "description": "Datos incompletos o inválidos"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "cliente_id": 12,
                                "condicion": "contado",
                                "notas": "Pedido web #5521",
                                "lineas": [
                                    {
                                        "sku": "FIL-001",
                                        "cantidad": 2
                                    },
                                    {
                                        "sku": "ACE-010",
                                        "cantidad": 1,
                                        "precio": 1200
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/v1/facturas/{numero}": {
            "get": {
                "summary": "Una factura con sus líneas. También por NCF.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "numero": "FAC-000120",
                                        "total": 1062,
                                        "lineas": [
                                            {
                                                "tipo": "producto",
                                                "descripcion": "Filtro de aceite Toyota",
                                                "cantidad": 2,
                                                "precio": 450,
                                                "descuento": 0,
                                                "total": 1062
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "numero",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/v1/ordenes/{numero}": {
            "get": {
                "summary": "Una orden de trabajo con estado, líneas e historial.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "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": []
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "numero",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/v1/cotizaciones/{numero}": {
            "get": {
                "summary": "Una cotización con sus líneas.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "numero": "COT-000012",
                                        "estado": "pendiente",
                                        "total": 14000,
                                        "vence": "2026-10-07",
                                        "lineas": []
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    }
                },
                "parameters": [
                    {
                        "name": "numero",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/v1/citas": {
            "post": {
                "summary": "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.",
                "security": [
                    {
                        "llave": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "numero": "AG-000015",
                                        "fecha": "2026-09-25",
                                        "hora": "10:00 am",
                                        "estado": "programada"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Llave inválida o revocada"
                    },
                    "403": {
                        "description": "La llave no tiene ese alcance"
                    },
                    "404": {
                        "description": "No existe"
                    },
                    "422": {
                        "description": "Datos incompletos o inválidos"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "nombre": "Pedro Web",
                                "telefono": "8095550000",
                                "vehiculo": "Hyundai Accent 2019",
                                "motivo": "Cambio de aceite",
                                "fecha": "2026-09-25",
                                "hora": "10:00",
                                "notas": "Viene con prisa"
                            }
                        }
                    }
                }
            }
        }
    }
}