{"openapi": "3.1.0", "info": {"title": "tuGerente API", "version": "1.0", "description": "\nAPI de **lectura** de tuGerente: consulta el cat\u00e1logo, los clientes, los documentos de venta\ny compra, las existencias y el equipo de tu organizaci\u00f3n desde cualquier herramienta externa\n\u2014una integraci\u00f3n propia, un Zap o un tablero.\n\nTodas las rutas cuelgan de `https://api.tugerente.co/v1/` y devuelven JSON.\n\n## Autenticaci\u00f3n\n\nCada petici\u00f3n se autentica con una **clave de API de la organizaci\u00f3n**, que se emite en el\npanel en *Configuraci\u00f3n \u2192 Integraciones* y se muestra una sola vez. La clave act\u00faa en nombre\nde la organizaci\u00f3n (no de una persona) y hoy solo concede el scope de lectura `read`; una\nclave sin ese scope recibe `403`.\n\n```bash\ncurl -H \"Authorization: Bearer sk_abc123_...\" \\\n  \"https://api.tugerente.co/v1/products/?q=cafe\"\n```\n\nUna credencial expuesta no se edita: se revoca y se acu\u00f1a otra. Esta p\u00e1gina es p\u00fablica, pero\ntodos los endpoints exigen clave.\n\n<!-- ReDoc-Inject: <security-definitions> -->\n\n## Qu\u00e9 datos ves\n\nLa clave determina la organizaci\u00f3n: **solo ver\u00e1s datos de esa organizaci\u00f3n** y un\nidentificador de otra responde `404`, nunca datos ajenos. Los registros archivados quedan\nfuera por defecto (p\u00eddelos con `archived=true` donde exista el filtro) y la papelera no se\nexpone en ning\u00fan caso.\n\n## Paginaci\u00f3n\n\nLas listas devuelven un sobre estable de dos claves:\n\n```json\n{\n  \"items\": [ ... ],\n  \"pagination\": {\n    \"page\": 1, \"per_page\": 15, \"total_pages\": 4, \"total_items\": 52,\n    \"has_next\": true, \"has_previous\": false,\n    \"next_page\": 2, \"previous_page\": null,\n    \"start_index\": 1, \"end_index\": 15\n  }\n}\n```\n\nRecorre las p\u00e1ginas con `?page=`; el tama\u00f1o de p\u00e1gina es fijo. Pedir una p\u00e1gina fuera de\nrango devuelve la \u00faltima.\n\n## Filtros y orden\n\nCada recurso declara sus propios par\u00e1metros \u2014b\u00fasqueda de texto `q`, rangos de fecha\n`<campo>_after` / `<campo>_before`, identificadores relacionados, banderas\u2014 y todos est\u00e1n\ndocumentados en su endpoint. Los filtros de selecci\u00f3n m\u00faltiple se repiten\n(`?category=3&category=7`) y `ordering` acepta varios campos separados por comas, con `-`\npara descendente (`?ordering=-updated_at,name`).\n\nEl filtrado es **tolerante**: un par\u00e1metro con un valor inv\u00e1lido se ignora en lugar de\nromper la petici\u00f3n, de modo que la lista nunca se vac\u00eda por un error de tipeo.\n\n## Sincronizaci\u00f3n incremental\n\nPara sincronizar sin releer todo, filtra por `updated_at_after` y guarda el\n`updated_at` m\u00e1s alto que recibiste. El orden por defecto (`updated_at` descendente, y el\n`id` como desempate) es estable, y los servicios que modifican un documento \u2014totales,\ncambios de estado, l\u00edneas, movimientos de stock\u2014 actualizan `updated_at` del documento\npadre, as\u00ed que un cambio en una l\u00ednea tambi\u00e9n aparece en el sondeo.\n\n## Errores\n\nLos errores devuelven JSON con la clave `detail`:\n\n| C\u00f3digo | Significado                                                        |\n| ------ | ------------------------------------------------------------------ |\n| `401`  | Falta la cabecera `Authorization`, o la clave es inv\u00e1lida, revocada o expir\u00f3. |\n| `403`  | La clave no tiene el scope necesario para la operaci\u00f3n.            |\n| `404`  | El recurso no existe **o** no pertenece a tu organizaci\u00f3n.         |\n\n## L\u00edmites de uso\n\nEl borde aplica l\u00edmites de tasa por clave y por direcci\u00f3n IP. Un cliente que sondea de forma\nrazonable (por ejemplo, cada pocos minutos con `updated_at_after`) no los alcanza; ante\nr\u00e1fagas sostenidas las peticiones se rechazan temporalmente.\n\n## Versionado\n\nLa versi\u00f3n va en la ruta (`/v1/`). Los cambios aditivos \u2014campos, filtros o recursos\nnuevos\u2014 se publican sin avisar y tu cliente debe ignorar lo que no conozca. Los cambios\nque rompen compatibilidad (quitar o renombrar campos, cambiar valores por defecto) estrenan\nuna versi\u00f3n nueva, que convive con esta.\n\n\u00bfDudas o algo que falte? Escr\u00edbenos a [soporte@tugerente.com](mailto:soporte@tugerente.com).\n", "contact": {"name": "Soporte tuGerente", "url": "https://tugerente.com", "email": "soporte@tugerente.com"}, "termsOfService": "https://app.tugerente.co/terminos/"}, "paths": {"/v1/products/": {"get": {"operationId": "list_products", "summary": "Listar productos", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "category", "in": "query", "required": false, "description": "Categor\u00eda", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "unit_of_measure", "in": "query", "required": false, "description": "Unidad", "schema": {"type": "string", "enum": ["unit", "package", "hour", "minute", "day", "session", "service", "metre", "gram", "kilogram", "litre"]}}, {"name": "is_salable", "in": "query", "required": false, "description": "Vendible", "schema": {"type": "boolean"}}, {"name": "is_purchaseable", "in": "query", "required": false, "description": "Comprable", "schema": {"type": "boolean"}}, {"name": "is_stocked", "in": "query", "required": false, "description": "Inventariable", "schema": {"type": "boolean"}}, {"name": "is_assembly", "in": "query", "required": false, "description": "Ensamble", "schema": {"type": "boolean"}}, {"name": "is_component", "in": "query", "required": false, "description": "Componente", "schema": {"type": "boolean"}}, {"name": "created_at_after", "in": "query", "required": false, "description": "Creado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "created_at_before", "in": "query", "required": false, "description": "Creado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "archived", "in": "query", "required": false, "description": "Archivado", "schema": {"type": "boolean"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `name`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_ProductOut_"}}}}}, "description": "Lista paginada de productos de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["products"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/products/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/products/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/products/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/products/{item_id}/": {"get": {"operationId": "retrieve_products", "summary": "Obtener un producto", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProductOut"}}}}}, "description": "Devuelve un producto por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["products"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/products/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/products/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/products/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/customers/": {"get": {"operationId": "list_customers", "summary": "Listar clientes", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "category", "in": "query", "required": false, "description": "Categor\u00eda", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "country", "in": "query", "required": false, "description": "Pa\u00eds", "schema": {"items": {"type": "string", "enum": ["AR", "BO", "BR", "CL", "EC", "SV", "MX", "PE", "US", "UY", "VE"]}, "type": "array"}}, {"name": "language", "in": "query", "required": false, "description": "Idioma", "schema": {"type": "string", "enum": ["es", "es-mx", "en"]}}, {"name": "tax_id_type", "in": "query", "required": false, "description": "Tipo de identificaci\u00f3n fiscal", "schema": {"type": "string", "enum": ["bo_nit", "us_ein", "eu_vat", "mx_rfc", "pe_ruc", "generic"]}}, {"name": "tax_exempt", "in": "query", "required": false, "description": "Situaci\u00f3n fiscal", "schema": {"type": "string", "enum": ["none", "exempt", "reverse"]}}, {"name": "created_at_after", "in": "query", "required": false, "description": "Creado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "created_at_before", "in": "query", "required": false, "description": "Creado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "archived", "in": "query", "required": false, "description": "Archivado", "schema": {"type": "boolean"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `name`, `code`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_CustomerOut_"}}}}}, "description": "Lista paginada de clientes de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["customers"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/customers/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/customers/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/customers/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/customers/{item_id}/": {"get": {"operationId": "retrieve_customers", "summary": "Obtener un cliente", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomerOut"}}}}}, "description": "Devuelve un cliente por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["customers"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/customers/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/customers/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/customers/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/quotes/": {"get": {"operationId": "list_quotes", "summary": "Listar cotizaciones", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "Estado", "schema": {"type": "string", "enum": ["draft", "sent", "accepted", "rejected", "expired"]}}, {"name": "customer", "in": "query", "required": false, "description": "Cliente", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "document_date_after", "in": "query", "required": false, "description": "Fecha (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "document_date_before", "in": "query", "required": false, "description": "Fecha (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "archived", "in": "query", "required": false, "description": "Archivado", "schema": {"type": "boolean"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `number`, `document_date`, `total_amount`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_QuoteOut_"}}}}}, "description": "Lista paginada de cotizaciones de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["quotes"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/quotes/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/quotes/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/quotes/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/quotes/{item_id}/": {"get": {"operationId": "retrieve_quotes", "summary": "Obtener una cotizaci\u00f3n", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuoteOut"}}}}}, "description": "Devuelve una cotizaci\u00f3n por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["quotes"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/quotes/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/quotes/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/quotes/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/orders/": {"get": {"operationId": "list_orders", "summary": "Listar pedidos", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "Estado", "schema": {"type": "string", "enum": ["draft", "confirmed", "fulfilled", "cancelled"]}}, {"name": "customer", "in": "query", "required": false, "description": "Cliente", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "document_date_after", "in": "query", "required": false, "description": "Fecha (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "document_date_before", "in": "query", "required": false, "description": "Fecha (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `number`, `document_date`, `total_amount`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_SalesDocumentOut_"}}}}}, "description": "Lista paginada de pedidos de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/orders/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/orders/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/orders/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/orders/{item_id}/": {"get": {"operationId": "retrieve_orders", "summary": "Obtener un pedido", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SalesDocumentOut"}}}}}, "description": "Devuelve un pedido por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/orders/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/orders/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/orders/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/invoices/": {"get": {"operationId": "list_invoices", "summary": "Listar facturas", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "Estado", "schema": {"type": "string", "enum": ["draft", "issued", "void"]}}, {"name": "customer", "in": "query", "required": false, "description": "Cliente", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "document_date_after", "in": "query", "required": false, "description": "Fecha (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "document_date_before", "in": "query", "required": false, "description": "Fecha (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `number`, `document_date`, `total_amount`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_SalesDocumentOut_"}}}}}, "description": "Lista paginada de facturas de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["invoices"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/invoices/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/invoices/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/invoices/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/invoices/{item_id}/": {"get": {"operationId": "retrieve_invoices", "summary": "Obtener una factura", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SalesDocumentOut"}}}}}, "description": "Devuelve una factura por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["invoices"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/invoices/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/invoices/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/invoices/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/suppliers/": {"get": {"operationId": "list_suppliers", "summary": "Listar proveedores", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "category", "in": "query", "required": false, "description": "Categor\u00eda", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "archived", "in": "query", "required": false, "description": "Archivado", "schema": {"type": "boolean"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `name`, `code`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_SupplierOut_"}}}}}, "description": "Lista paginada de proveedores de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["suppliers"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/suppliers/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/suppliers/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/suppliers/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/suppliers/{item_id}/": {"get": {"operationId": "retrieve_suppliers", "summary": "Obtener un proveedor", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SupplierOut"}}}}}, "description": "Devuelve un proveedor por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["suppliers"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/suppliers/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/suppliers/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/suppliers/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/purchase-orders/": {"get": {"operationId": "list_purchase_orders", "summary": "Listar \u00f3rdenes de compra", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "Estado", "schema": {"type": "string", "enum": ["draft", "placed", "partial", "received", "cancelled"]}}, {"name": "supplier", "in": "query", "required": false, "description": "Proveedor", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `number`, `total_amount`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_PurchaseOrderOut_"}}}}}, "description": "Lista paginada de \u00f3rdenes de compra de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["purchase_orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/purchase-orders/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/purchase-orders/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/purchase-orders/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/purchase-orders/{item_id}/": {"get": {"operationId": "retrieve_purchase_orders", "summary": "Obtener una orden de compra", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PurchaseOrderOut"}}}}}, "description": "Devuelve una orden de compra por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["purchase_orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/purchase-orders/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/purchase-orders/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/purchase-orders/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/build-orders/": {"get": {"operationId": "list_build_orders", "summary": "Listar \u00f3rdenes de fabricaci\u00f3n", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "Estado", "schema": {"type": "string", "enum": ["draft", "in_progress", "done", "cancelled"]}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `number`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_BuildOrderOut_"}}}}}, "description": "Lista paginada de \u00f3rdenes de fabricaci\u00f3n de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["build_orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/build-orders/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/build-orders/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/build-orders/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/build-orders/{item_id}/": {"get": {"operationId": "retrieve_build_orders", "summary": "Obtener una orden de fabricaci\u00f3n", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BuildOrderOut"}}}}}, "description": "Devuelve una orden de fabricaci\u00f3n por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["build_orders"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/build-orders/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/build-orders/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/build-orders/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/stock/": {"get": {"operationId": "list_stock", "summary": "Listar existencias", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "warehouse", "in": "query", "required": false, "description": "Almac\u00e9n", "schema": {"items": {"type": "integer"}, "type": "array"}}, {"name": "lot_expiry", "in": "query", "required": false, "description": "Vencimiento", "schema": {"type": "string", "enum": ["expiring_soon", "expired"]}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `quantity`, `product__name`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_StockOut_"}}}}}, "description": "Lista paginada de existencias de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["stock"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/stock/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/stock/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/stock/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/stock/{item_id}/": {"get": {"operationId": "retrieve_stock", "summary": "Obtener una existencia", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StockOut"}}}}}, "description": "Devuelve una existencia por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["stock"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/stock/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/stock/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/stock/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/price-lists/": {"get": {"operationId": "list_price_lists", "summary": "Listar listas de precios", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "archived", "in": "query", "required": false, "description": "Archivado", "schema": {"type": "boolean"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `name`, `created_at`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_PriceListOut_"}}}}}, "description": "Lista paginada de listas de precios de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["price_lists"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/price-lists/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/price-lists/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/price-lists/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/price-lists/{item_id}/": {"get": {"operationId": "retrieve_price_lists", "summary": "Obtener una lista de precios", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PriceListOut"}}}}}, "description": "Devuelve una lista de precios por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["price_lists"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/price-lists/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/price-lists/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/price-lists/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}, "/v1/team/": {"get": {"operationId": "list_team", "summary": "Listar miembros del equipo", "parameters": [{"name": "q", "in": "query", "required": false, "description": "Buscar", "schema": {"type": "string"}}, {"name": "capability", "in": "query", "required": false, "description": "Capacidades", "schema": {"items": {"type": "string", "enum": ["sell", "purchase"]}, "type": "array"}}, {"name": "is_active", "in": "query", "required": false, "description": "Estado", "schema": {"type": "boolean"}}, {"name": "has_login", "in": "query", "required": false, "description": "Acceso", "schema": {"type": "boolean"}}, {"name": "created_at_after", "in": "query", "required": false, "description": "Creado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "created_at_before", "in": "query", "required": false, "description": "Creado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_after", "in": "query", "required": false, "description": "Actualizado (desde)", "schema": {"format": "date", "type": "string"}}, {"name": "updated_at_before", "in": "query", "required": false, "description": "Actualizado (hasta)", "schema": {"format": "date", "type": "string"}}, {"name": "ordering", "in": "query", "required": false, "description": "Orden, separado por comas; prefija `-` para descendente. Campos: `name`, `code`, `created`, `updated_at`.", "schema": {"type": "string"}}, {"name": "page", "in": "query", "required": false, "description": "N\u00famero de p\u00e1gina (desde 1). Fuera de rango devuelve la \u00faltima p\u00e1gina.", "schema": {"type": "integer", "minimum": 1, "default": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ApiList_TeamMemberOut_"}}}}}, "description": "Lista paginada de miembros del equipo de tu organizaci\u00f3n. Los filtros son opcionales y un valor inv\u00e1lido se ignora en lugar de vaciar la lista.", "tags": ["team"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/team/?updated_at_after=2026-01-01&page=1\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nclient = httpx.Client(\n    base_url=\"https://api.tugerente.co\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\nparams = {\"updated_at_after\": \"2026-01-01\", \"page\": 1}\n\nwhile True:\n    response = client.get(\"/v1/team/\", params=params)\n    response.raise_for_status()\n    payload = response.json()\n\n    for item in payload[\"items\"]:\n        print(item[\"id\"])\n\n    # El tama\u00f1o de p\u00e1gina es fijo: `has_next` es la \u00fanica condici\u00f3n de parada.\n    if not payload[\"pagination\"][\"has_next\"]:\n        break\n\n    params[\"page\"] = payload[\"pagination\"][\"next_page\"]"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/team/?updated_at_after=2026-01-01&page=1\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\n// El sobre de lista: `items` y `pagination`; sigue con `pagination.next_page`.\nconst { items, pagination } = await response.json();\nconsole.log(items.length, pagination.total_items);"}]}}, "/v1/team/{item_id}/": {"get": {"operationId": "retrieve_team", "summary": "Obtener un miembro del equipo", "parameters": [{"in": "path", "name": "item_id", "schema": {"title": "Item Id", "type": "integer"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TeamMemberOut"}}}}}, "description": "Devuelve un miembro del equipo por su identificador. Un identificador de otra organizaci\u00f3n responde `404`.", "tags": ["team"], "security": [{"ApiKeyAuth": []}], "x-codeSamples": [{"lang": "bash", "label": "cURL", "source": "curl -sS \\\n  -H \"Authorization: Bearer $TUGERENTE_API_KEY\" \\\n  \"https://api.tugerente.co/v1/team/42/\""}, {"lang": "Python", "label": "Python", "source": "import os\n\nimport httpx\n\n\nresponse = httpx.get(\n    \"https://api.tugerente.co/v1/team/42/\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TUGERENTE_API_KEY']}\"},\n    timeout=30,\n)\n\n# 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nresponse.raise_for_status()\nprint(response.json())"}, {"lang": "JavaScript", "label": "JavaScript", "source": "const url = \"https://api.tugerente.co/v1/team/42/\";\n\nconst response = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TUGERENTE_API_KEY}` },\n});\n// 404 significa que no existe o que pertenece a otra organizaci\u00f3n.\nif (!response.ok) throw new Error(`tuGerente API ${response.status}`);\n\nconst item = await response.json();"}]}}}, "components": {"schemas": {"ApiList_ProductOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/ProductOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[ProductOut]", "type": "object"}, "PaginationProps": {"description": "JSON-safe pagination metadata for a page-number paginated list.", "properties": {"page": {"title": "Page", "type": "integer"}, "per_page": {"title": "Per Page", "type": "integer"}, "total_pages": {"title": "Total Pages", "type": "integer"}, "total_items": {"title": "Total Items", "type": "integer"}, "has_next": {"title": "Has Next", "type": "boolean"}, "has_previous": {"title": "Has Previous", "type": "boolean"}, "next_page": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Next Page"}, "previous_page": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Previous Page"}, "start_index": {"title": "Start Index", "type": "integer"}, "end_index": {"title": "End Index", "type": "integer"}}, "required": ["page", "per_page", "total_pages", "total_items", "has_next", "has_previous", "next_page", "previous_page", "start_index", "end_index"], "title": "PaginationProps", "type": "object"}, "ProductOut": {"description": "A product as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "sku": {"title": "Sku", "type": "string"}, "description": {"title": "Description", "type": "string"}, "unit_of_measure": {"title": "Unit Of Measure", "type": "string"}, "category_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Category Id"}, "is_salable": {"title": "Is Salable", "type": "boolean"}, "is_purchaseable": {"title": "Is Purchaseable", "type": "boolean"}, "is_stocked": {"title": "Is Stocked", "type": "boolean"}, "is_assembly": {"title": "Is Assembly", "type": "boolean"}, "is_component": {"title": "Is Component", "type": "boolean"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "archived_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Archived At"}}, "required": ["id", "name", "sku", "description", "unit_of_measure", "category_id", "is_salable", "is_purchaseable", "is_stocked", "is_assembly", "is_component", "created_at", "updated_at", "archived_at"], "title": "ProductOut", "type": "object"}, "ApiList_CustomerOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/CustomerOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[CustomerOut]", "type": "object"}, "CustomerOut": {"description": "A customer as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "code": {"title": "Code", "type": "string"}, "business_name": {"title": "Business Name", "type": "string"}, "individual_name": {"title": "Individual Name", "type": "string"}, "email": {"title": "Email", "type": "string"}, "phone": {"title": "Phone", "type": "string"}, "country": {"title": "Country", "type": "string"}, "language": {"title": "Language", "type": "string"}, "tax_id": {"title": "Tax Id", "type": "string"}, "tax_id_type": {"title": "Tax Id Type", "type": "string"}, "tax_exempt": {"title": "Tax Exempt", "type": "string"}, "category_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Category Id"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "archived_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Archived At"}}, "required": ["id", "code", "business_name", "individual_name", "email", "phone", "country", "language", "tax_id", "tax_id_type", "tax_exempt", "category_id", "created_at", "updated_at", "archived_at"], "title": "CustomerOut", "type": "object"}, "ApiList_QuoteOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/QuoteOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[QuoteOut]", "type": "object"}, "QuoteOut": {"description": "A quote: the only archivable sales document (orders cancel, invoices void).", "properties": {"id": {"title": "Id", "type": "integer"}, "number": {"title": "Number", "type": "string"}, "status": {"title": "Status", "type": "string"}, "customer_id": {"title": "Customer Id", "type": "integer"}, "document_date": {"anyOf": [{"format": "date", "type": "string"}, {"type": "null"}], "title": "Document Date"}, "currency": {"title": "Currency", "type": "string"}, "subtotal_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Subtotal Amount", "type": "string"}, "discount_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Discount Amount", "type": "string"}, "tax_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Tax Amount", "type": "string"}, "total_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Total Amount", "type": "string"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "archived_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Archived At"}}, "required": ["id", "number", "status", "customer_id", "document_date", "currency", "subtotal_amount", "discount_amount", "tax_amount", "total_amount", "created_at", "updated_at", "archived_at"], "title": "QuoteOut", "type": "object"}, "ApiList_SalesDocumentOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/SalesDocumentOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[SalesDocumentOut]", "type": "object"}, "SalesDocumentOut": {"description": "A sales document (quote/order/invoice) as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "number": {"title": "Number", "type": "string"}, "status": {"title": "Status", "type": "string"}, "customer_id": {"title": "Customer Id", "type": "integer"}, "document_date": {"anyOf": [{"format": "date", "type": "string"}, {"type": "null"}], "title": "Document Date"}, "currency": {"title": "Currency", "type": "string"}, "subtotal_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Subtotal Amount", "type": "string"}, "discount_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Discount Amount", "type": "string"}, "tax_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Tax Amount", "type": "string"}, "total_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Total Amount", "type": "string"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "number", "status", "customer_id", "document_date", "currency", "subtotal_amount", "discount_amount", "tax_amount", "total_amount", "created_at", "updated_at"], "title": "SalesDocumentOut", "type": "object"}, "ApiList_SupplierOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/SupplierOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[SupplierOut]", "type": "object"}, "SupplierOut": {"description": "A supplier as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "code": {"title": "Code", "type": "string"}, "name": {"title": "Name", "type": "string"}, "email": {"title": "Email", "type": "string"}, "phone": {"title": "Phone", "type": "string"}, "tax_id": {"title": "Tax Id", "type": "string"}, "category_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Category Id"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "archived_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Archived At"}}, "required": ["id", "code", "name", "email", "phone", "tax_id", "category_id", "created_at", "updated_at", "archived_at"], "title": "SupplierOut", "type": "object"}, "ApiList_PurchaseOrderOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/PurchaseOrderOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[PurchaseOrderOut]", "type": "object"}, "PurchaseOrderOut": {"description": "A purchase order as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "number": {"title": "Number", "type": "string"}, "status": {"title": "Status", "type": "string"}, "supplier_id": {"title": "Supplier Id", "type": "integer"}, "currency": {"title": "Currency", "type": "string"}, "subtotal_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Subtotal Amount", "type": "string"}, "tax_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Tax Amount", "type": "string"}, "total_amount": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Total Amount", "type": "string"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "number", "status", "supplier_id", "currency", "subtotal_amount", "tax_amount", "total_amount", "created_at", "updated_at"], "title": "PurchaseOrderOut", "type": "object"}, "ApiList_BuildOrderOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/BuildOrderOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[BuildOrderOut]", "type": "object"}, "BuildOrderOut": {"description": "A build order as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "number": {"title": "Number", "type": "string"}, "status": {"title": "Status", "type": "string"}, "product_id": {"title": "Product Id", "type": "integer"}, "warehouse_id": {"title": "Warehouse Id", "type": "integer"}, "quantity": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Quantity", "type": "string"}, "completed_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Completed At"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "number", "status", "product_id", "warehouse_id", "quantity", "completed_at", "created_at", "updated_at"], "title": "BuildOrderOut", "type": "object"}, "ApiList_StockOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/StockOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[StockOut]", "type": "object"}, "StockOut": {"description": "A stock bucket (product x warehouse balance) as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "product_id": {"title": "Product Id", "type": "integer"}, "variant_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Variant Id"}, "warehouse_id": {"title": "Warehouse Id", "type": "integer"}, "quantity": {"pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "title": "Quantity", "type": "string"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "product_id", "variant_id", "warehouse_id", "quantity", "created_at", "updated_at"], "title": "StockOut", "type": "object"}, "ApiList_PriceListOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/PriceListOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[PriceListOut]", "type": "object"}, "PriceListOut": {"description": "A price list as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "category_id": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Category Id"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}, "archived_at": {"anyOf": [{"format": "date-time", "type": "string"}, {"type": "null"}], "title": "Archived At"}}, "required": ["id", "name", "category_id", "created_at", "updated_at", "archived_at"], "title": "PriceListOut", "type": "object"}, "ApiList_TeamMemberOut_": {"properties": {"items": {"items": {"$ref": "#/components/schemas/TeamMemberOut"}, "title": "Items", "type": "array"}, "pagination": {"$ref": "#/components/schemas/PaginationProps"}}, "required": ["items", "pagination"], "title": "ApiList[TeamMemberOut]", "type": "object"}, "TeamMemberOut": {"description": "A team member as the API promises it.", "properties": {"id": {"title": "Id", "type": "integer"}, "display_name": {"title": "Display Name", "type": "string"}, "job_title": {"title": "Job Title", "type": "string"}, "email": {"title": "Email", "type": "string"}, "code": {"title": "Code", "type": "string"}, "capabilities": {"items": {"type": "string"}, "title": "Capabilities", "type": "array"}, "is_active": {"title": "Is Active", "type": "boolean"}, "created_at": {"format": "date-time", "title": "Created At", "type": "string"}, "updated_at": {"format": "date-time", "title": "Updated At", "type": "string"}}, "required": ["id", "display_name", "job_title", "email", "code", "capabilities", "is_active", "created_at", "updated_at"], "title": "TeamMemberOut", "type": "object"}}, "securitySchemes": {"ApiKeyAuth": {"type": "http", "bearerFormat": "sk_<prefix>_<secreto>", "description": "Clave de API de la organizaci\u00f3n, emitida en el panel (Configuraci\u00f3n \u2192 Integraciones) y mostrada una sola vez. Env\u00edala en `Authorization: Bearer sk_\u2026` en cada petici\u00f3n.", "scheme": "bearer"}}}, "servers": [{"url": "https://api.tugerente.co", "description": "API de tuGerente"}], "tags": [{"name": "products", "x-displayName": "Productos", "description": "Cat\u00e1logo de productos y servicios. Requiere el scope `read` (`api.read.products`)."}, {"name": "price_lists", "x-displayName": "Listas de precios", "description": "Listas de precios por categor\u00eda de cliente. Requiere el scope `read` (`api.read.price_lists`)."}, {"name": "customers", "x-displayName": "Clientes", "description": "Clientes de la organizaci\u00f3n, con su categor\u00eda y datos fiscales. Requiere el scope `read` (`api.read.customers`)."}, {"name": "quotes", "x-displayName": "Cotizaciones", "description": "Cotizaciones (`COT`) con su estado y totales. Requiere el scope `read` (`api.read.quotes`)."}, {"name": "orders", "x-displayName": "Pedidos", "description": "Pedidos (`PED`) con su estado y totales. Requiere el scope `read` (`api.read.orders`)."}, {"name": "invoices", "x-displayName": "Facturas", "description": "Facturas (`FAC`) emitidas, incluidas las anuladas. Requiere el scope `read` (`api.read.invoices`)."}, {"name": "suppliers", "x-displayName": "Proveedores", "description": "Proveedores de la organizaci\u00f3n. Requiere el scope `read` (`api.read.suppliers`)."}, {"name": "purchase_orders", "x-displayName": "\u00d3rdenes de compra", "description": "\u00d3rdenes de compra (`OC`) y su avance de recepci\u00f3n. Requiere el scope `read` (`api.read.purchase_orders`)."}, {"name": "build_orders", "x-displayName": "\u00d3rdenes de fabricaci\u00f3n", "description": "\u00d3rdenes de fabricaci\u00f3n (`OF`) y su estado. Requiere el scope `read` (`api.read.build_orders`)."}, {"name": "stock", "x-displayName": "Existencias", "description": "Existencias por producto y almac\u00e9n. Requiere el scope `read` (`api.read.stock`)."}, {"name": "team", "x-displayName": "Miembros del equipo", "description": "Miembros del equipo. Requiere el scope `read` (`api.read.team`)."}], "x-tagGroups": [{"name": "Cat\u00e1logo", "tags": ["products", "price_lists"]}, {"name": "Ventas", "tags": ["customers", "quotes", "orders", "invoices"]}, {"name": "Compras", "tags": ["suppliers", "purchase_orders"]}, {"name": "Operaciones", "tags": ["stock", "build_orders"]}, {"name": "Organizaci\u00f3n", "tags": ["team"]}]}