# Variables del workspace

`met.variables` guarda dos cosas del workspace: **variables de valor** (configuración y secretos, como el token de una API externa) y las **definiciones de los campos personalizados** de tu CRM. Lo primero necesita el scope `variables:write` para escribir; lo segundo te deja descubrir qué claves acepta un contacto.

```ts
const met = new Met(key, { workspaceId });
```

## Variables de valor

Una variable es un par `name` → `value` que vive en el workspace. Con `set()` haces upsert por nombre (crea o actualiza según exista): es la forma más cómoda.

```ts
await met.variables.set('mi_api_token', 'sk_live_...', { encrypted: true });

const vars = await met.variables.list();   // no devuelve secretos en claro
```

Marca `encrypted: true` para tokens y secretos: el valor se guarda cifrado y `list()` ya no lo devuelve en claro. Si prefieres las operaciones explícitas (por id), tienes `create`, `update` y `delete`:

```ts
const v = await met.variables.create({
  name: 'saludo',
  value: '¡Hola!',
  description: 'Texto por defecto',
});                                         // POST /variables (variables:write)

await met.variables.update(v.id, { value: '¡Bienvenido!' });
await met.variables.delete(v.id);
```

> `set()` corre un `list()` para buscar el nombre; si vas a escribir muchas variables seguidas, usa `create`/`update` directo con el id que ya tienes.

## Token → Función HTTP

El caso estrella: una [Función HTTP](funciones-y-flujos.html) resuelve su token de autenticación por **nombre de variable**, no en crudo. Guardas el token una vez y la Función lo referencia con `auth_workspace_variable`; Meteor lo envía como `Authorization: Bearer <valor>` al llamar tu endpoint.

```ts
// 1. Guarda el secreto (cifrado)
await met.variables.set('mi_api_token', 'sk_live_...', { encrypted: true });

// 2. La Función lo referencia por nombre
await met.functions.create({
  name: 'consultar_precio',
  description: 'Consulta el precio de un producto en la API externa',
  http: {
    url: 'https://api.example.com/precio',
    method: 'POST',
    auth_workspace_variable: 'mi_api_token',
  },
});
```

Así el token nunca queda escrito en la definición de la Función. Para rotarlo, un solo `set()` con el mismo nombre lo reemplaza y todas las Funciones que lo usan quedan al día.

## Definiciones de campos del CRM

Los campos personalizados de un contacto viven en su `data` con la **clave pelada** (`etapa`, `monto`); los campos de sistema llevan `$` (`$name`, `$status`). Para saber qué claves existen y qué opciones acepta un `select`, descubre el catálogo:

```ts
const defs = await met.variables.fieldDefinitions();   // variables:read
const etapas = defs.find((d) => d.field_key === 'etapa')?.options ?? [];

await met.contacts.update(42, { data: { etapa: etapas[0] } });
```

Cada definición trae `field_key`, `label`, `type` (`text` · `number` · `select` · `currency` · `date` · …) y `options`. También puedes gestionarlas por código:

```ts
const campo = await met.variables.createFieldDefinition({
  field_key: 'etapa',
  label: 'Etapa',
  type: 'select',
  options: ['Nuevo', 'Contactado', 'Cerrado'],
});

await met.variables.updateFieldDefinition(campo.id, { options: [...campo.options, 'Perdido'] });
await met.variables.deleteFieldDefinition(campo.id);
```

`field_key` y `type` no se editan: cambiarlos rompería los valores ya guardados en los contactos. Solo ajustas `label`, `description` y `options`.

> Para leer y escribir esos valores en cada contacto, mira [Contactos (CRM)](contactos.html).
