> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filexpress.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Proyectos

> Consultar proyectos con su resumen financiero, crearlos y vincularles documentos

| Permiso | Endpoints |
| - | - |
| `projects` | `GET /projects`, `GET /projects/{id}` |
| `projects.write` | `POST /projects`, `PUT /projects/{id}`, `POST /projects/{id}/items` |

<Note>
  Son permisos **explícitos**: deben marcarse uno por uno en **Integraciones externas**; las integraciones existentes no los reciben automáticamente.
</Note>

**Estados de un proyecto** (`status`):

| Valor | Significado |
| - | - |
| `planned` | Planificado |
| `in_progress` | En curso |
| `on_hold` | En pausa |
| `completed` | Completado |
| `cancelled` | Cancelado |

## Objeto proyecto

```json theme={null}
{
  "id": "9e01...",
  "name": "Remodelación oficinas Grupo Alfa",
  "status": "in_progress",
  "customer": { "id": "9c77...", "name": "Grupo Alfa, S.A. de C.V." },
  "branch_id": "9d1c5a3e-...",
  "start_date": "2026-09-01",
  "end_date": "2026-12-15",
  "budget": 25000.0,
  "description": "Obra civil y mobiliario",
  "quotation_id": null,
  "created_at": "2026-08-28T09:30:00-06:00"
}
```

`customer.name` es la razón social del cliente o, si no tiene, su nombre comercial.

## Listar proyectos

```http theme={null}
GET /projects?status=in_progress
```

| Parámetro | Tipo | Requerido | Descripción |
| - | - | - | - |
| `status` | string | No | Uno de los estados. |
| `customer_id` | string | No | Filtra por cliente. |
| `search` | string | No | Busca en el nombre (máx. 100). |
| `per_page` | integer | No | 1 a 200 (por defecto 50). |

Devuelve `data` (objetos proyecto, del más reciente por fecha de inicio) y `pagination`. No incluye proyectos eliminados.

## Consultar proyecto

```http theme={null}
GET /projects/{id}
```

Devuelve el objeto proyecto más su resumen financiero en `summary`:

```json theme={null}
{
  "status": true,
  "data": {
    "id": "9e01...",
    "name": "Remodelación oficinas Grupo Alfa",
    "status": "in_progress",
    "...": "...",
    "summary": {
      "total_sales": 18000.0,
      "total_expenses": 9500.0,
      "total_payroll": 3200.0,
      "total_work_orders": 800.0,
      "total_costs": 13500.0,
      "profit": 4500.0,
      "margin_percent": 25.0,
      "budget": 25000.0,
      "budget_used_percent": 54.0,
      "counts": { "sales": 3, "expenses": 12, "payrolls": 2, "work_orders": 1 }
    }
  }
}
```

| Campo | Cálculo |
| - | - |
| `total_sales` | Total a pagar de las ventas vinculadas **procesadas** y no anuladas, del ambiente del negocio. |
| `total_expenses` | Total a pagar de las compras vinculadas no anuladas ni eliminadas, del ambiente del negocio. |
| `total_payroll` | Total de las planillas vinculadas no eliminadas. |
| `total_work_orders` | Total de las órdenes de trabajo del proyecto. |
| `total_costs` | `total_expenses + total_payroll + total_work_orders`. |
| `profit` | `total_sales − total_costs`. |
| `margin_percent` | `profit / total_sales × 100`; `null` si no hay ventas. |
| `budget_used_percent` | `total_costs / budget × 100`; `null` si el proyecto no tiene presupuesto. |
| `counts` | Cantidad de ventas, compras, planillas y órdenes de trabajo consideradas. |

**Errores**: `404` `Project not found` (inexistente, eliminado o de otro negocio).

## Crear proyecto

```http theme={null}
POST /projects
```

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `name` | string | Sí | Nombre (máx. 255). |
| `customer_id` | string | Sí | Cliente de una sucursal del negocio. |
| `start_date` | date | Sí | `YYYY-MM-DD`. |
| `status` | string | Sí | Uno de los estados. |
| `branch_id` | string | No | Sucursal del negocio. |
| `end_date` | date | No | `YYYY-MM-DD`. |
| `budget` | number | No | Presupuesto (≥ 0). Se usa para `budget_used_percent`. |
| `description` | string | No | Máx. 2000 caracteres. |

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/projects \
  -H "X-API-Key: fx_xxxxxxxx" \
  -H "Idempotency-Key: proyecto-PRJ-2026-014" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Remodelación oficinas Grupo Alfa",
    "customer_id": "9c77...",
    "start_date": "2026-09-01",
    "end_date": "2026-12-15",
    "budget": 25000,
    "status": "planned"
  }'
```

**Respuesta `201`**: el objeto proyecto. Acepta [`Idempotency-Key`](/docs/api/introduccion#idempotencia).

**Errores**

| Código | Causa |
| - | - |
| `422` | Validación, `Branch not found` o `Customer not found` (de otro negocio o inexistente). |
| `409` | Conflicto de `Idempotency-Key`. |

## Actualizar proyecto

```http theme={null}
PUT /projects/{id}
```

Mismos campos que la creación, todos opcionales: solo se modifican los enviados. Responde `200` con el objeto actualizado.

**Errores**: `404` `Project not found`; `422` validación, `Branch not found` o `Customer not found`.

## Vincular documentos

```http theme={null}
POST /projects/{id}/items
```

Asigna ventas, compras o planillas al proyecto para que cuenten en su resumen. Si un documento ya estaba en otro proyecto, pasa a este.

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `type` | string | Sí | `sale`, `expense` o `payroll`. |
| `ids` | array | Sí | 1 a 500 IDs del tipo indicado. |

```json theme={null}
{
  "type": "sale",
  "ids": ["9a10...", "9a11...", "id-de-otro-negocio"]
}
```

**Respuesta `200`**

```json theme={null}
{
  "status": true,
  "data": {
    "linked": 2,
    "rejected_ids": ["id-de-otro-negocio"],
    "summary": { "total_sales": 18000.0, "...": "..." }
  }
}
```

Solo se vinculan documentos del mismo negocio. Los IDs inexistentes o de otro negocio no producen error: se devuelven en `rejected_ids`. `summary` es el resumen financiero ya recalculado.

**Errores**: `404` `Project not found`; `422` validación.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.