Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eme2dev/Eme2App/llms.txt

Use this file to discover all available pages before exploring further.

The Clients API manages the customer master record for each company (empresa). Every client is scoped to a single empresa_id derived from the authenticated user’s JWT, so calls across tenants are impossible by design. Clients carry full Spanish fiscal metadata — tax regime (regimen_fiscal_id), fiscal territory (territorio_fiscal_id), IRPF withholding regime (regimen_irpf_id), an optional default payment term, and an optional accounting sub-account (cuenta_contable_ventas). The NIF is stored normalised to uppercase and is enforced unique per company at the database level, though the API returns an advisory nif_existente object instead of blocking the write — see NIF advisory behaviour below.

Authentication

All endpoints require a valid JWT in the Authorization header. The token must belong to an active user with role admin or user who is linked to an active empresa.
Authorization: Bearer <token>

Endpoints

MethodPathDescription
GET/api/clientesList all active clients
GET/api/clientes/siguiente-codigoGet the next available numeric code
GET/api/clientes/:idGet a single client by ID
POST/api/clientesCreate a new client
PUT/api/clientes/:idUpdate an existing client
PATCH/api/clientes/:id/estadoToggle active / inactive status
DELETE/api/clientes/:idSoft-delete a client

GET /api/clientes

Returns all clients that have estado = true (active) for the authenticated company.
curl -X GET https://api.eme2app.es/api/clientes \
  -H "Authorization: Bearer <token>"

Response

{
  "estado": "exito",
  "datos": [
    {
      "id": "a1b2c3d4-...",
      "nombre": "Acme SL",
      "nif": "B12345678",
      "email": "facturacion@acme.es",
      "telefono": "912345678",
      "direccion": "Calle Mayor 1",
      "codigo_postal": "28001",
      "localidad": "Madrid",
      "provincia": "Madrid",
      "regimen_fiscal_id": "...",
      "territorio_fiscal_id": "...",
      "regimen_irpf_id": "...",
      "forma_pago_defecto_id": null,
      "cuenta_contable_ventas": "430001",
      "estado": true,
      "created_at": "2024-01-15T10:00:00.000Z"
    }
  ],
  "total": 1
}
estado
string
Always "exito" on success.
datos
array
Array of active client objects.
total
number
Count of records returned.

GET /api/clientes/siguiente-codigo

Returns the next sequential numeric code to assign to a new client. The value is read from the contadores table for the authenticated company.
curl -X GET https://api.eme2app.es/api/clientes/siguiente-codigo \
  -H "Authorization: Bearer <token>"

Response

{
  "estado": "exito",
  "datos": { "siguiente": 42 }
}
datos.siguiente
number
The next available integer code (current counter value + 1).

GET /api/clientes/:id

Returns a single client record. Returns 404 if the client does not exist or belongs to a different company.
curl -X GET https://api.eme2app.es/api/clientes/a1b2c3d4-e5f6-... \
  -H "Authorization: Bearer <token>"

Path parameters

id
string
required
UUID of the client.

Response 200

{
  "estado": "exito",
  "datos": { "id": "a1b2c3d4-...", "nombre": "Acme SL", ... }
}

Response 404

{
  "estado": "error",
  "mensaje": "Cliente no encontrado"
}

POST /api/clientes

Creates a new client record for the authenticated company.
curl -X POST https://api.eme2app.es/api/clientes \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "nombre": "Acme SL",
    "nif": "B12345678",
    "email": "facturacion@acme.es",
    "telefono": "912345678",
    "direccion": "Calle Mayor 1",
    "codigo_postal": "28001",
    "localidad": "Madrid",
    "provincia": "Madrid",
    "regimen_fiscal_id": "uuid-regimen-fiscal",
    "territorio_fiscal_id": "uuid-territorio",
    "regimen_irpf_id": "uuid-irpf",
    "forma_pago_defecto_id": "uuid-forma-pago",
    "cuenta_contable_ventas": "430001"
  }'

Body parameters

nombre
string
required
Full legal name of the client. Whitespace is trimmed automatically.
nif
string
required
Tax identification number (NIF/CIF). Stored normalised to uppercase. Unique per empresa at the database level; see NIF advisory behaviour.
email
string
Contact email address. Must pass standard email format validation when provided.
telefono
string
Phone number. No format enforcement; whitespace is trimmed.
direccion
string
Street address. Max 500 characters.
codigo_postal
string
Postal code. Whitespace is trimmed.
localidad
string
City / municipality. Whitespace is trimmed.
provincia
string
Province. Whitespace is trimmed.
regimen_fiscal_id
string
required
UUID of a regimenes_fiscales record belonging to the authenticated company (e.g. Régimen General, Régimen Simplificado).
territorio_fiscal_id
string
required
UUID of a territorios_fiscales record (e.g. Territorio Común, País Vasco, Navarra).
regimen_irpf_id
string
required
UUID of a regimenes_irpf record. Controls the IRPF withholding percentage applied on invoices.
forma_pago_defecto_id
string
UUID of a formas_pago record. Must exist, belong to the authenticated company, and have activo = true. Returns 400 if the payment term is inactive or not found.
cuenta_contable_ventas
string
Sales sub-ledger account code. Max 12 characters. Used when exporting to accounting software.

Response 201

{
  "estado": "exito",
  "mensaje": "Cliente creado exitosamente",
  "datos": { "id": "a1b2c3d4-...", "nombre": "Acme SL", ... }
}

NIF advisory behaviour

The POST /api/clientes and PUT /api/clientes/:id endpoints never block a write because of a duplicate NIF. Instead, if another client record in the same company already holds the same NIF, the response includes an extra nif_existente object alongside the newly created or updated record. This lets the frontend surface a warning without failing the operation.The mensaje is also adjusted to flag the situation:
{
  "estado": "exito",
  "mensaje": "Cliente creado. Ya existía un cliente desactivado con ese NIF.",
  "datos": { "id": "new-uuid-...", "nombre": "Acme SL", ... },
  "nif_existente": {
    "cliente_id": "old-uuid-...",
    "nombre": "Acme Antigua SL",
    "activo": false
  }
}
When nif_existente.activo is true the existing client is still live — the API still succeeds but the frontend should prompt the user to review the conflict.

Response 400 — inactive payment term

{
  "estado": "error",
  "mensaje": "La forma de pago predefinida debe estar activa"
}

Response 400 — validation failure

{
  "estado": "error",
  "mensaje": "El NIF es requerido"
}

PUT /api/clientes/:id

Full update of an existing client. Accepts the same body fields as POST. Returns 404 if the client does not exist in the company scope.
curl -X PUT https://api.eme2app.es/api/clientes/a1b2c3d4-e5f6-... \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "nombre": "Acme Solutions SL",
    "nif": "B12345678",
    "regimen_fiscal_id": "uuid-regimen-fiscal",
    "territorio_fiscal_id": "uuid-territorio",
    "regimen_irpf_id": "uuid-irpf"
  }'

Path parameters

id
string
required
UUID of the client to update.
The request body accepts the same fields as POST /api/clientes — all fields validated by the same rule set. The NIF advisory check is also applied: if the incoming NIF differs from the current value and matches another client in the company, a nif_existente object is returned in the response.

Response 200

{
  "estado": "exito",
  "mensaje": "Cliente actualizado exitosamente",
  "datos": { "id": "a1b2c3d4-...", "nombre": "Acme Solutions SL", ... }
}

PATCH /api/clientes/:id/estado

Toggles the client between active (true) and inactive (false) without deleting it. Inactive clients are excluded from the GET /api/clientes list but can still be referenced by existing invoices.
curl -X PATCH https://api.eme2app.es/api/clientes/a1b2c3d4-e5f6-.../estado \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "activo": false }'

Path parameters

id
string
required
UUID of the client.

Body parameters

activo
boolean
required
Pass true to activate the client, false to deactivate. Any non-boolean value returns a 400 error.

Response 200

{
  "estado": "exito",
  "mensaje": "Cliente desactivado",
  "datos": { "id": "a1b2c3d4-...", "estado": false, ... }
}

DELETE /api/clientes/:id

Soft-deletes the client. The record is not physically removed from the database; the operation is always reversible via PATCH /:id/estado. Returns 404 if the client is not found within the company.
curl -X DELETE https://api.eme2app.es/api/clientes/a1b2c3d4-e5f6-... \
  -H "Authorization: Bearer <token>"

Path parameters

id
string
required
UUID of the client to delete.

Response 200

{
  "estado": "exito",
  "mensaje": "Cliente eliminado exitosamente",
  "datos": { "id": "a1b2c3d4-...", ... }
}
Because this is a soft-delete, existing invoices and budget documents that reference the client remain intact and continue to display the client’s name and fiscal data correctly.

Error reference

HTTP statusestadoTypical mensaje
400errorValidation error detail (e.g. "El nombre es requerido")
400error"La forma de pago predefinida debe estar activa"
400error"El campo activo debe ser booleano"
404error"Cliente no encontrado"
500errorInternal server error message

Build docs developers (and LLMs) love