@vitrina/api 11.41.0 → 11.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.cts +3073 -284
  2. package/dist/index.d.ts +3073 -284
  3. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -14836,6 +14836,8 @@ interface paths {
14836
14836
  * Phase 2 (tenencia_source): `tenencia_source` COMPOSES with `tenencia` rather than narrowing it — `?tenencia=propio&tenencia_source=decided` is "propio, and a person or a document actually settled that" (`decided` ⇒ `tenencia_source <> 'default'`); `document` / `declared` / `default` match the column exactly. See `POST /vehicles/tenencia` for how a `declared` row is produced.
14837
14837
  *
14838
14838
  * SIN COSTO (ADR 0114 §8). A car that entered without a compra (nota de compra), a consignación (contrato) or a parte de pago (nota de venta) has no acquisition, so nothing records what it cost. Every row carries `sin_costo: true` for such a unit (any status), and `view=sin_costo` lists the pile still on the floor — active, not vendido, no acquisition; the SAME predicate as the `sin_costo` count on `GET /vehicles/stats` and the `stock_without_cost` dealer alert. It is never a gate: bulk imports and migrations land cars here on purpose. `sin_costo` is a statement about the cost basis and follows the cost omission above: ABSENT without `dealership_economics:read`.
14839
+ *
14840
+ * MANDATO SIN FIRMAR (ADR 0114 §5). `view=mandato_sin_firmar` lists the cars whose consignación (activa or vendida) has an emitted mandato and no signed copy filed in the expediente — the SAME predicate as the `mandato_sin_firmar` count on `GET /vehicles/stats` and the `mandate_unsigned` dealer alert. Never a gate.
14839
14841
  */
14840
14842
  get: {
14841
14843
  parameters: {
@@ -14862,7 +14864,7 @@ interface paths {
14862
14864
  consignacion_modalidad?: "en_local" | "virtual" | "sin_contrato";
14863
14865
  tenencia_source?: "document" | "declared" | "default" | "decided";
14864
14866
  without_acquisition?: boolean | string;
14865
- view?: "published" | "unpublished" | "error" | "stale" | "source_deactivated" | "sin_costo";
14867
+ view?: "published" | "unpublished" | "error" | "stale" | "source_deactivated" | "sin_costo" | "mandato_sin_firmar";
14866
14868
  active?: boolean | string;
14867
14869
  sort?: "price_asc" | "price_desc" | "year_desc" | "recent" | "days_desc" | "interest_desc" | "estacionamiento";
14868
14870
  limit?: number;
@@ -15357,7 +15359,7 @@ interface paths {
15357
15359
  query?: {
15358
15360
  format?: "xlsx" | "pdf";
15359
15361
  q?: string;
15360
- view?: "published" | "unpublished" | "error" | "stale" | "source_deactivated" | "sin_costo";
15362
+ view?: "published" | "unpublished" | "error" | "stale" | "source_deactivated" | "sin_costo" | "mandato_sin_firmar";
15361
15363
  location_id?: string;
15362
15364
  status?: "disponible" | "reservado" | "vendido";
15363
15365
  vehicle_type?: "auto" | "camion" | "maquinaria" | "nautico";
@@ -16348,7 +16350,7 @@ interface paths {
16348
16350
  };
16349
16351
  /**
16350
16352
  * A vehicle's change history (Historial)
16351
- * @description Reverse-chronological audit trail for this vehicle — created, field edits (with a before→after diff), publish/unpublish/cierre, and Override local protect/release — with teammate actors resolved to display names. The UI merges it with /activity (leads) into one "Leads y cambios" timeline.
16353
+ * @description Reverse-chronological audit trail for this vehicle — created, field edits (with a before→after diff), publish/unpublish/cierre, and Override local protect/release — with teammate actors resolved to display names. It also carries the deal's milestones, read from each document's own audit rows: nota de compra emitted/voided (`purchase_note_issued`, `purchase_note_voided`), nota de venta emitted/approved/voided (`sale_note_issued`, `sale_note_approved`, `sale_note_voided`), contrato de compraventa first printed (`compraventa_printed`), mandato de consignación first printed (`mandato_issued`), a signed copy filed (`signed_copy_filed`, with `metadata.signed_document_type`) and the liquidación paid to the consignor (`liquidacion_paid`). `metadata.folio` names the document when it has one. Each document type appears only for a caller holding its read scope (`purchase_notes:read`, `sale_notes:read`, `consignments:read`; signed copies also need `vehicle_registry:read`). A download of the Resumen del negocio is `deal_settlement_downloaded`. The UI merges it with /activity (leads) into one "Leads y cambios" timeline.
16352
16354
  */
16353
16355
  get: {
16354
16356
  parameters: {
@@ -16373,6 +16375,22 @@ interface paths {
16373
16375
  * @example {
16374
16376
  * "data": [
16375
16377
  * {
16378
+ * "id": "99999999-0000-4000-8000-000000000005",
16379
+ * "action": "sale_notes.approve",
16380
+ * "kind": "sale_note_approved",
16381
+ * "actor": {
16382
+ * "kind": "user",
16383
+ * "id": "11111111-0000-4000-8000-000000000001",
16384
+ * "name": "Ana Torres"
16385
+ * },
16386
+ * "changes": [],
16387
+ * "metadata": {
16388
+ * "folio": "V-13",
16389
+ * "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001"
16390
+ * },
16391
+ * "at": "2026-09-18T15:02:11.000Z"
16392
+ * },
16393
+ * {
16376
16394
  * "id": "99999999-0000-4000-8000-000000000003",
16377
16395
  * "action": "vehicles.create",
16378
16396
  * "kind": "created",
@@ -29103,7 +29121,9 @@ interface paths {
29103
29121
  put?: never;
29104
29122
  /**
29105
29123
  * Record an outbound preference (consent or DNC) for a contact
29106
- * @description Appends one fact. **Revoking is a POST with the opposite `status`** — the superseded row stays readable as evidence, which is why there is no PATCH or DELETE here.
29124
+ * @description Appends one fact. **Revoking a block your team set is a POST with the opposite `status`** — the superseded row stays readable as evidence, which is why there is no PATCH or DELETE here.
29125
+ *
29126
+ * An opt-out the **customer** asked for (their message, an unsubscribe link, their own «BAJA») cannot be revoked here: any `status` other than `blocked` that would end it answers 409 with `details.code` `customer_opt_out_lift_required`. Lifting it takes a team member in the Vitrina app, from the contact's card, after confirming.
29107
29127
  *
29108
29128
  * `recorded_at` is stamped by the server and is deliberately not settable: a caller who could backdate a consent fact could manufacture evidence. `legal_basis` is free text recorded verbatim («consentimiento explícito, Ley 21.719») and `evidence_message_id` points at the customer message that proves it, when there is one.
29109
29129
  *
@@ -32008,6 +32028,7 @@ interface paths {
32008
32028
  *
32009
32029
  * * **409** when the sale’s price is below the level this organisation requires an authorisation for and no APPROVED `price_approval` names this document (BR-433/BR-434 — a sale cannot authorise its own discount). Raise one with `POST /price-approvals` and have somebody else decide it. The refusal deliberately states no figure: the shortfall and the reference are cost disclosures gated on `dealership_economics:read`.
32010
32030
  * * **409** when the unit has already been sold by another document.
32031
+ * * **409** when the car is consigned (active contrato de consignación) and its mandato was never emitted — «Emite el mandato antes de aprobar» (`details.reason: mandate_not_emitted`). Emit it with `POST /consignments/{id}/contract`.
32011
32032
  * * **409** when the document is already approved, or is voided — an approval names a person and a moment and cannot be restated.
32012
32033
  * * **400** when the deal’s board has no Won column, or forbids the move onto it.
32013
32034
  *
@@ -33556,6 +33577,8 @@ interface paths {
33556
33577
  *
33557
33578
  * Returns the document WITH its line items in document order. `corrected_at` / `corrected_by` say whether it has been changed since it was issued, and by whom.
33558
33579
  *
33580
+ * It also carries the unit it bought, the same as each row of the list: `vehicle` is `{ id, make, model, year, registration_number }` or `null`, and `vehicle_count` says how many units the document acquired (`vehicle` is the FIRST of them when there are several, and `null` exactly when the count is `0`).
33581
+ *
33559
33582
  * A document belonging to another workspace is a 404, indistinguishable from one that does not exist.
33560
33583
  */
33561
33584
  get: {
@@ -33594,7 +33617,15 @@ interface paths {
33594
33617
  * "void_reason": null,
33595
33618
  * "voided_by": null,
33596
33619
  * "created_at": "2026-09-12T10:15:00.000Z",
33597
- * "updated_at": "2026-09-12T10:15:00.000Z"
33620
+ * "updated_at": "2026-09-12T10:15:00.000Z",
33621
+ * "vehicle": {
33622
+ * "id": "e1e1e1e1-0000-4000-8000-000000000001",
33623
+ * "make": "Mazda",
33624
+ * "model": "CX-5",
33625
+ * "year": 2020,
33626
+ * "registration_number": "KXPT21"
33627
+ * },
33628
+ * "vehicle_count": 1
33598
33629
  * }
33599
33630
  * }
33600
33631
  */
@@ -33819,7 +33850,7 @@ interface paths {
33819
33850
  };
33820
33851
  /**
33821
33852
  * Print the nota de compra
33822
- * @description The nota de compra as a printable PDF (`application/pdf`, served `inline`) on the dealership’s paper: folio, seller, vehicle, lines and totals. Rendered on demand and not stored. Any status prints; a voided note says «Anulada». Accepts the UUID or the folio (`P-47`). Requires `purchase_notes:read`.
33853
+ * @description The nota de compra as a printable PDF (`application/pdf`, served `inline`) on the dealership’s paper, drawn from the workspace’s default nota de compra template (the standard text when there is none): folio, the seller and the dealership with RUT and domicilio, the vehicle, the price with its retentions and the amount paid to the seller, detail lines and signatures. A fact the seller’s contact lacks prints «【PENDIENTE: …】» rather than refusing the print. Rendered on demand and not stored. Any status prints; a voided note says «Anulada». Accepts the UUID or the folio (`P-47`). Requires `purchase_notes:read`.
33823
33854
  */
33824
33855
  get: {
33825
33856
  parameters: {
@@ -34172,6 +34203,349 @@ interface paths {
34172
34203
  patch?: never;
34173
34204
  trace?: never;
34174
34205
  };
34206
+ "/document-templates/clauses/check": {
34207
+ parameters: {
34208
+ query?: never;
34209
+ header?: never;
34210
+ path?: never;
34211
+ cookie?: never;
34212
+ };
34213
+ get?: never;
34214
+ put?: never;
34215
+ /**
34216
+ * Check a body against its cláusulas esenciales and recomendadas
34217
+ * @description The editor's checklist («Esenciales 5/5 · Recomendadas 5/6», ADR 0114 §6.1), computed by the same function the publish gate uses. Send the body being written plus `template_id` (it is that template's next version: its current version is the baseline for "removed") or `document_kind` (a new template: the standard text is the baseline). Returns each clause with `present`, a `summary` of counts, `missing_esenciales` (publishing is refused while non-empty) and `removed_recomendadas` (each needs a reason in `recommended_clause_removals` when publishing). A clause is detected by structural markers — the `{{VARIABLES}}` it needs (designed blocks count, through their text twins), a section heading, or a signature block — never by free-text search. Writes nothing. Requires `document_templates:read`.
34218
+ */
34219
+ post: {
34220
+ parameters: {
34221
+ query?: never;
34222
+ header?: {
34223
+ /** @description Replay-safe retries: resending the SAME key with the SAME body returns the original response (`X-Idempotent-Replay: 1`) instead of creating a second copy — safe to send whenever a response might not have arrived. The same key with a DIFFERENT body answers `409 IDEMPOTENCY_KEY_CONFLICT`; use a fresh key per operation. */
34224
+ "Idempotency-Key"?: string;
34225
+ };
34226
+ path?: never;
34227
+ cookie?: never;
34228
+ };
34229
+ requestBody?: {
34230
+ content: {
34231
+ /**
34232
+ * @example {
34233
+ * "template_id": "3b1f8a52-9d34-4a7e-8f2c-1a2b3c4d5e6f",
34234
+ * "body": "# Nota de venta N° {{FOLIO}}\n\n{{BLOQUE_PARTES}}\n\n{{BLOQUE_VEHICULO}}\n\n{{BLOQUE_PRECIO}}\n\n{{BLOQUE_FIRMAS}}"
34235
+ * }
34236
+ */
34237
+ "application/json": {
34238
+ body: string;
34239
+ /** Format: uuid */
34240
+ template_id?: string;
34241
+ document_kind?: string;
34242
+ };
34243
+ };
34244
+ };
34245
+ responses: {
34246
+ /** @description The clause checklist */
34247
+ 200: {
34248
+ headers: {
34249
+ [name: string]: unknown;
34250
+ };
34251
+ content: {
34252
+ /**
34253
+ * @example {
34254
+ * "data": {
34255
+ * "document_kind": "sale_note",
34256
+ * "esenciales": [
34257
+ * {
34258
+ * "key": "partes",
34259
+ * "label": "Partes con RUT y domicilio",
34260
+ * "tier": "esencial",
34261
+ * "present": true,
34262
+ * "description": "Partes con RUT y domicilio."
34263
+ * },
34264
+ * {
34265
+ * "key": "vehiculo",
34266
+ * "label": "Identidad del vehículo",
34267
+ * "tier": "esencial",
34268
+ * "present": true,
34269
+ * "description": "Identidad del vehículo."
34270
+ * },
34271
+ * {
34272
+ * "key": "precio",
34273
+ * "label": "Precio en cifras y palabras",
34274
+ * "tier": "esencial",
34275
+ * "present": true,
34276
+ * "description": "Precio en cifras y palabras."
34277
+ * },
34278
+ * {
34279
+ * "key": "pago",
34280
+ * "label": "Forma de pago",
34281
+ * "tier": "esencial",
34282
+ * "present": true,
34283
+ * "description": "Forma de pago."
34284
+ * },
34285
+ * {
34286
+ * "key": "firmas",
34287
+ * "label": "Firmas",
34288
+ * "tier": "esencial",
34289
+ * "present": true,
34290
+ * "description": "Firmas."
34291
+ * }
34292
+ * ],
34293
+ * "recomendadas": [
34294
+ * {
34295
+ * "key": "folio",
34296
+ * "label": "Número de folio",
34297
+ * "tier": "recomendada",
34298
+ * "present": true,
34299
+ * "description": "Número de folio."
34300
+ * },
34301
+ * {
34302
+ * "key": "vendedor",
34303
+ * "label": "Vendedor de la automotora",
34304
+ * "tier": "recomendada",
34305
+ * "present": true,
34306
+ * "description": "Vendedor de la automotora."
34307
+ * },
34308
+ * {
34309
+ * "key": "chasis",
34310
+ * "label": "N° de chasis (VIN)",
34311
+ * "tier": "recomendada",
34312
+ * "present": true,
34313
+ * "description": "N° de chasis (VIN)."
34314
+ * },
34315
+ * {
34316
+ * "key": "kilometraje",
34317
+ * "label": "Kilometraje",
34318
+ * "tier": "recomendada",
34319
+ * "present": true,
34320
+ * "description": "Kilometraje."
34321
+ * },
34322
+ * {
34323
+ * "key": "impuesto_transferencia",
34324
+ * "label": "Impuesto a la transferencia",
34325
+ * "tier": "recomendada",
34326
+ * "present": true,
34327
+ * "description": "Impuesto a la transferencia."
34328
+ * },
34329
+ * {
34330
+ * "key": "condiciones",
34331
+ * "label": "Condiciones",
34332
+ * "tier": "recomendada",
34333
+ * "present": false,
34334
+ * "description": "Condiciones."
34335
+ * }
34336
+ * ],
34337
+ * "summary": {
34338
+ * "esenciales": {
34339
+ * "present": 5,
34340
+ * "total": 5
34341
+ * },
34342
+ * "recomendadas": {
34343
+ * "present": 5,
34344
+ * "total": 6
34345
+ * }
34346
+ * },
34347
+ * "missing_esenciales": [],
34348
+ * "removed_recomendadas": [
34349
+ * {
34350
+ * "key": "condiciones",
34351
+ * "label": "Condiciones",
34352
+ * "description": "La sección «Condiciones» con los términos del documento.",
34353
+ * "tier": "recomendada",
34354
+ * "present": false
34355
+ * }
34356
+ * ]
34357
+ * }
34358
+ * }
34359
+ */
34360
+ "application/json": {
34361
+ data?: unknown;
34362
+ meta?: {
34363
+ [key: string]: unknown;
34364
+ };
34365
+ };
34366
+ };
34367
+ };
34368
+ /** @description Validation error */
34369
+ 400: {
34370
+ headers: {
34371
+ [name: string]: unknown;
34372
+ };
34373
+ content: {
34374
+ "application/json": components["schemas"]["Error"];
34375
+ };
34376
+ };
34377
+ /** @description Unauthorized */
34378
+ 401: {
34379
+ headers: {
34380
+ [name: string]: unknown;
34381
+ };
34382
+ content: {
34383
+ "application/json": components["schemas"]["Error"];
34384
+ };
34385
+ };
34386
+ /** @description Forbidden */
34387
+ 403: {
34388
+ headers: {
34389
+ [name: string]: unknown;
34390
+ };
34391
+ content: {
34392
+ "application/json": components["schemas"]["Error"];
34393
+ };
34394
+ };
34395
+ /** @description Not found */
34396
+ 404: {
34397
+ headers: {
34398
+ [name: string]: unknown;
34399
+ };
34400
+ content: {
34401
+ "application/json": components["schemas"]["Error"];
34402
+ };
34403
+ };
34404
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
34405
+ 409: {
34406
+ headers: {
34407
+ [name: string]: unknown;
34408
+ };
34409
+ content: {
34410
+ "application/json": components["schemas"]["Error"];
34411
+ };
34412
+ };
34413
+ /** @description Rate limited */
34414
+ 429: {
34415
+ headers: {
34416
+ [name: string]: unknown;
34417
+ };
34418
+ content: {
34419
+ "application/json": components["schemas"]["Error"];
34420
+ };
34421
+ };
34422
+ };
34423
+ };
34424
+ delete?: never;
34425
+ options?: never;
34426
+ head?: never;
34427
+ patch?: never;
34428
+ trace?: never;
34429
+ };
34430
+ "/document-templates/{id}/preview-values": {
34431
+ parameters: {
34432
+ query?: never;
34433
+ header?: never;
34434
+ path?: never;
34435
+ cookie?: never;
34436
+ };
34437
+ /**
34438
+ * Placeholder values of the latest issued document of a template's type
34439
+ * @description What the template preview renders against: the `{{NAME}}` values of the most recent documento emitido of the template's document type, built by the SAME code that prints that document, so the preview cannot drift from the print. Covers `sale_note`, `compraventa`, `deal_settlement` (Resumen del negocio), `consignment` (mandato), `consignment_settlement` (liquidación) and `purchase_note` (nota de compra); reserva, cotización and ficha técnica print fixed layouts and have no values source. The designed blocks (`BLOQUE_PARTES`, `BLOQUE_VEHICULO`, `BLOQUE_PRECIO`, `BLOQUE_FIRMAS`) are values too: each is the block's text form filled with the same document's values (a fact the document lacks reads «【PENDIENTE: …】»). `source` names the document (`display_id`: the folio such as `V-12`, or the patente for a consignment, and when it was issued); it is `null` — with an empty `values` — when none exists or the type has no values source; the caller then falls back to the vocabulary examples. A fact the document lacks is absent from `values`, never blank. The values carry buyer/owner identity and money, so this requires `document_templates:read` AND the read scope of that document (`sale_notes:read` for nota de venta and compraventa, `consignments:read` for the two consignment families, `dealership_economics:read` for the Resumen del negocio, `purchase_notes:read` for the nota de compra). Writes and issues nothing.
34440
+ */
34441
+ get: {
34442
+ parameters: {
34443
+ query?: never;
34444
+ header?: never;
34445
+ path: {
34446
+ id: string;
34447
+ };
34448
+ cookie?: never;
34449
+ };
34450
+ requestBody?: never;
34451
+ responses: {
34452
+ /** @description The source document and its placeholder values */
34453
+ 200: {
34454
+ headers: {
34455
+ [name: string]: unknown;
34456
+ };
34457
+ content: {
34458
+ /**
34459
+ * @example {
34460
+ * "data": {
34461
+ * "document_kind": "sale_note",
34462
+ * "source": {
34463
+ * "document_kind": "sale_note",
34464
+ * "id": "5c1a3f0e-8b7d-4e2a-9c61-2d4f6a8b0c13",
34465
+ * "display_id": "V-12",
34466
+ * "issued_at": "2026-09-29T15:20:00.000Z"
34467
+ * },
34468
+ * "values": {
34469
+ * "FOLIO": "V-12",
34470
+ * "FECHA": "29 de septiembre de 2026",
34471
+ * "COMPRADOR_NOMBRE": "Persona Ejemplo",
34472
+ * "VEHICULO_PATENTE": "AB-CD-12"
34473
+ * }
34474
+ * }
34475
+ * }
34476
+ */
34477
+ "application/json": {
34478
+ data?: unknown;
34479
+ meta?: {
34480
+ [key: string]: unknown;
34481
+ };
34482
+ };
34483
+ };
34484
+ };
34485
+ /** @description Validation error */
34486
+ 400: {
34487
+ headers: {
34488
+ [name: string]: unknown;
34489
+ };
34490
+ content: {
34491
+ "application/json": components["schemas"]["Error"];
34492
+ };
34493
+ };
34494
+ /** @description Unauthorized */
34495
+ 401: {
34496
+ headers: {
34497
+ [name: string]: unknown;
34498
+ };
34499
+ content: {
34500
+ "application/json": components["schemas"]["Error"];
34501
+ };
34502
+ };
34503
+ /** @description Forbidden */
34504
+ 403: {
34505
+ headers: {
34506
+ [name: string]: unknown;
34507
+ };
34508
+ content: {
34509
+ "application/json": components["schemas"]["Error"];
34510
+ };
34511
+ };
34512
+ /** @description Not found */
34513
+ 404: {
34514
+ headers: {
34515
+ [name: string]: unknown;
34516
+ };
34517
+ content: {
34518
+ "application/json": components["schemas"]["Error"];
34519
+ };
34520
+ };
34521
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
34522
+ 409: {
34523
+ headers: {
34524
+ [name: string]: unknown;
34525
+ };
34526
+ content: {
34527
+ "application/json": components["schemas"]["Error"];
34528
+ };
34529
+ };
34530
+ /** @description Rate limited */
34531
+ 429: {
34532
+ headers: {
34533
+ [name: string]: unknown;
34534
+ };
34535
+ content: {
34536
+ "application/json": components["schemas"]["Error"];
34537
+ };
34538
+ };
34539
+ };
34540
+ };
34541
+ put?: never;
34542
+ post?: never;
34543
+ delete?: never;
34544
+ options?: never;
34545
+ head?: never;
34546
+ patch?: never;
34547
+ trace?: never;
34548
+ };
34175
34549
  "/credit-applications": {
34176
34550
  parameters: {
34177
34551
  query?: never;
@@ -39279,6 +39653,205 @@ interface paths {
39279
39653
  patch?: never;
39280
39654
  trace?: never;
39281
39655
  };
39656
+ "/margin/preview": {
39657
+ parameters: {
39658
+ query?: never;
39659
+ header?: never;
39660
+ path?: never;
39661
+ cookie?: never;
39662
+ };
39663
+ get?: never;
39664
+ put?: never;
39665
+ /**
39666
+ * Preview the margin of a nota de venta being written
39667
+ * @description The margin a nota de venta WOULD leave if the unit sold today at `net_clp` — what the nota de venta form shows while the price is typed. The same preview the Resumen del negocio serves for a car with no live nota de venta (`GET /vehicles/{id}/deal-settlement`, `state: preview`), at the typed price instead of the published one: no add-ons, no seller commissions, and the one margin definition. The body is the deal-margin DTO of `GET /margin/deals/{id}` without `sale_note_id`, `display_id` and `salesperson_id` — no document exists yet.
39668
+ *
39669
+ * **A consigned unit is previewed on its contract’s economics**: the split is projected from the active contract’s comisión exactly as the liquidación will compute it (`settlement` carries the projection), so the dealership’s revenue is the comisión, never the whole price. A contract with no comisión on file has no split to project: its revenue is `null` with a `liquidacion` gap.
39670
+ *
39671
+ * `net_clp` is NET of IVA (cifras del negocio, ADR 0114 §2.2). The price a buyer agrees to on an afecto sale includes IVA, like the published price: send `round(price / 1,19)`. Writes nothing. Requires `dealership_economics:read`; 404 for a unit outside the workspace.
39672
+ */
39673
+ post: {
39674
+ parameters: {
39675
+ query?: never;
39676
+ header?: {
39677
+ /** @description Replay-safe retries: resending the SAME key with the SAME body returns the original response (`X-Idempotent-Replay: 1`) instead of creating a second copy — safe to send whenever a response might not have arrived. The same key with a DIFFERENT body answers `409 IDEMPOTENCY_KEY_CONFLICT`; use a fresh key per operation. */
39678
+ "Idempotency-Key"?: string;
39679
+ };
39680
+ path?: never;
39681
+ cookie?: never;
39682
+ };
39683
+ requestBody?: {
39684
+ content: {
39685
+ /**
39686
+ * @example {
39687
+ * "vehicle_id": "e5e5e5e5-0000-4000-8000-000000000002",
39688
+ * "net_clp": 10000000
39689
+ * }
39690
+ */
39691
+ "application/json": {
39692
+ /**
39693
+ * Format: uuid
39694
+ * @description The unit being sold.
39695
+ * @example 4b1c2d3e-5f60-4a7b-8c9d-0e1f2a3b4c5d
39696
+ */
39697
+ vehicle_id: string;
39698
+ /**
39699
+ * @description The sale price the nota de venta would record, NET of IVA, in whole CLP pesos. On an afecto sale that is the price the buyer pays divided by 1,19 (rounded); on an exento sale it is the price.
39700
+ * @example 10084034
39701
+ */
39702
+ net_clp: number;
39703
+ /**
39704
+ * @description The leg the sale would be issued under. Omitted = the leg the unit’s tenencia suggests (`consignante` for a consigned unit, `automotora` otherwise).
39705
+ * @enum {string}
39706
+ */
39707
+ seller_of_record?: "consignante" | "retoma" | "automotora";
39708
+ };
39709
+ };
39710
+ };
39711
+ responses: {
39712
+ /** @description The previewed deal margin */
39713
+ 200: {
39714
+ headers: {
39715
+ [name: string]: unknown;
39716
+ };
39717
+ content: {
39718
+ /**
39719
+ * @example {
39720
+ * "data": {
39721
+ * "vehicle_id": "e5e5e5e5-0000-4000-8000-000000000002",
39722
+ * "issued_at": "2026-09-29T15:00:00.000Z",
39723
+ * "period": "2026-09",
39724
+ * "regime": "consignacion",
39725
+ * "ingresos_clp": 800000,
39726
+ * "revenue_terms": {
39727
+ * "precio_venta_clp": 10000000,
39728
+ * "add_on_charges_clp": 0,
39729
+ * "pass_through_clp": 0,
39730
+ * "pass_through_paid_out_clp": 0,
39731
+ * "dealer_take_clp": 800000
39732
+ * },
39733
+ * "costo_venta_clp": 0,
39734
+ * "margen_bruto_clp": 800000,
39735
+ * "deductions": {
39736
+ * "comisiones_vendedores_clp": 0,
39737
+ * "gastos_adicionales_clp": 120000,
39738
+ * "gastos_unidad_clp": 120000,
39739
+ * "ingresos_unidad_clp": 0,
39740
+ * "desembolsos_add_on_clp": 0,
39741
+ * "gastos_fijos_clp": null
39742
+ * },
39743
+ * "margen_neto_clp": 680000,
39744
+ * "settlement": {
39745
+ * "settlement_mode": "stated_commission",
39746
+ * "amount_venta_clp": 10000000,
39747
+ * "monto_owner_clp": 9200000,
39748
+ * "deducciones_clp": 0
39749
+ * },
39750
+ * "cost_rollup": {
39751
+ * "acquisition_net_clp": 0,
39752
+ * "expense_total_clp": 120000,
39753
+ * "income_total_clp": 0,
39754
+ * "total_cost_clp": 120000,
39755
+ * "dealership_cost_clp": 120000,
39756
+ * "by_party": {
39757
+ * "automotora": {
39758
+ * "acquisition_clp": 0,
39759
+ * "expense_clp": 120000,
39760
+ * "income_clp": 0,
39761
+ * "total_clp": 120000
39762
+ * },
39763
+ * "dueno": {
39764
+ * "acquisition_clp": 0,
39765
+ * "expense_clp": 0,
39766
+ * "income_clp": 0,
39767
+ * "total_clp": 0
39768
+ * },
39769
+ * "cliente": {
39770
+ * "acquisition_clp": 0,
39771
+ * "expense_clp": 0,
39772
+ * "income_clp": 0,
39773
+ * "total_clp": 0
39774
+ * }
39775
+ * },
39776
+ * "entry_count": 2,
39777
+ * "complete": true,
39778
+ * "gaps": []
39779
+ * },
39780
+ * "complete": true,
39781
+ * "gaps": []
39782
+ * }
39783
+ * }
39784
+ */
39785
+ "application/json": {
39786
+ data?: unknown;
39787
+ meta?: {
39788
+ [key: string]: unknown;
39789
+ };
39790
+ };
39791
+ };
39792
+ };
39793
+ /** @description Validation error */
39794
+ 400: {
39795
+ headers: {
39796
+ [name: string]: unknown;
39797
+ };
39798
+ content: {
39799
+ "application/json": components["schemas"]["Error"];
39800
+ };
39801
+ };
39802
+ /** @description Unauthorized */
39803
+ 401: {
39804
+ headers: {
39805
+ [name: string]: unknown;
39806
+ };
39807
+ content: {
39808
+ "application/json": components["schemas"]["Error"];
39809
+ };
39810
+ };
39811
+ /** @description Forbidden */
39812
+ 403: {
39813
+ headers: {
39814
+ [name: string]: unknown;
39815
+ };
39816
+ content: {
39817
+ "application/json": components["schemas"]["Error"];
39818
+ };
39819
+ };
39820
+ /** @description Not found */
39821
+ 404: {
39822
+ headers: {
39823
+ [name: string]: unknown;
39824
+ };
39825
+ content: {
39826
+ "application/json": components["schemas"]["Error"];
39827
+ };
39828
+ };
39829
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
39830
+ 409: {
39831
+ headers: {
39832
+ [name: string]: unknown;
39833
+ };
39834
+ content: {
39835
+ "application/json": components["schemas"]["Error"];
39836
+ };
39837
+ };
39838
+ /** @description Rate limited */
39839
+ 429: {
39840
+ headers: {
39841
+ [name: string]: unknown;
39842
+ };
39843
+ content: {
39844
+ "application/json": components["schemas"]["Error"];
39845
+ };
39846
+ };
39847
+ };
39848
+ };
39849
+ delete?: never;
39850
+ options?: never;
39851
+ head?: never;
39852
+ patch?: never;
39853
+ trace?: never;
39854
+ };
39282
39855
  "/margin/export": {
39283
39856
  parameters: {
39284
39857
  query?: never;
@@ -39298,7 +39871,7 @@ interface paths {
39298
39871
  period?: components["schemas"]["OverheadPeriod"];
39299
39872
  from?: string;
39300
39873
  to?: string;
39301
- /** @description `xlsx` (a workbook, typed cells) or `csv` (UTF-8, RFC 4180). */
39874
+ /** @description `xlsx` (a workbook, typed cells) or `csv` (`;`-separated, UTF-8 with BOM, dd-mm-aaaa dates, decimal comma; the first sheet only). Date-times are on the America/Santiago clock in both formats. */
39302
39875
  format?: "xlsx" | "csv";
39303
39876
  };
39304
39877
  header?: never;
@@ -40020,7 +40593,7 @@ interface paths {
40020
40593
  get: {
40021
40594
  parameters: {
40022
40595
  query?: {
40023
- /** @description `xlsx` (a workbook, typed cells) or `csv` (UTF-8, RFC 4180). */
40596
+ /** @description `xlsx` (a workbook, typed cells) or `csv` (`;`-separated, UTF-8 with BOM, dd-mm-aaaa dates, decimal comma; the first sheet only). Date-times are on the America/Santiago clock in both formats. */
40024
40597
  format?: "xlsx" | "csv";
40025
40598
  };
40026
40599
  header?: never;
@@ -40122,7 +40695,7 @@ interface paths {
40122
40695
  from?: string;
40123
40696
  to?: string;
40124
40697
  status?: "issued" | "approved" | "voided";
40125
- /** @description `xlsx` (a workbook, typed cells) or `csv` (UTF-8, RFC 4180). */
40698
+ /** @description `xlsx` (a workbook, typed cells) or `csv` (`;`-separated, UTF-8 with BOM, dd-mm-aaaa dates, decimal comma; the first sheet only). Date-times are on the America/Santiago clock in both formats. */
40126
40699
  format?: "xlsx" | "csv";
40127
40700
  };
40128
40701
  header?: never;
@@ -40205,6 +40778,115 @@ interface paths {
40205
40778
  patch?: never;
40206
40779
  trace?: never;
40207
40780
  };
40781
+ "/insights/seller-performance/export": {
40782
+ parameters: {
40783
+ query?: never;
40784
+ header?: never;
40785
+ path?: never;
40786
+ cookie?: never;
40787
+ };
40788
+ /**
40789
+ * Exportar comisiones — the month-end payroll file (Excel or CSV)
40790
+ * @description The same figures as the report above, rendered as an .xlsx workbook (default) or, with `?format=csv`, a `;`-separated UTF-8 CSV of the ledger, on the same export rail as `GET /vehicles/export`: sheet "Comisiones" is one row per seller per deal with the commission arithmetic visible (base × «Tasa %» → comisión; rates are percentages, never basis points; dates are dd-mm-aaaa hh:mm on the America/Santiago clock), sheet "Resumen" is what to pay each person. Same `?window=` parameter and the same `dealership_economics:read` gate as the report — a file must not be pullable for a period or by a principal the screen refuses. `Content-Disposition` carries the generated filename (`comisiones-<periodo>-<YYYY-MM-DD>.xlsx`). Audited.
40791
+ */
40792
+ get: {
40793
+ parameters: {
40794
+ query?: {
40795
+ /** @description Which window. Omit it (with `from`/`to`) for an explicit range — the shape every ranged Insights report has always accepted. `calendar_month` is the one payroll wants: commission is paid monthly, and the month is the DEALERSHIP’s (America/Santiago), the same boundary the commission itself was resolved under. */
40796
+ window?: "24h" | "7d" | "30d" | "90d" | "calendar_month" | "calendar_year" | "custom";
40797
+ /** @description `window=calendar_month` only. ISO month, `YYYY-MM`. Defaults to the month in progress. */
40798
+ month?: string;
40799
+ /** @description `window=calendar_year` only. `YYYY`. Defaults to the year in progress. */
40800
+ year?: string;
40801
+ /** @description Explicit range only. ISO instant, INCLUSIVE. */
40802
+ from?: string;
40803
+ /** @description Explicit range only. ISO instant, EXCLUSIVE. */
40804
+ to?: string;
40805
+ /** @description `xlsx` (default; sheets "Comisiones" + "Resumen") or `csv` (the ledger: `;`-separated, UTF-8 with BOM, dd-mm-aaaa dates). */
40806
+ format?: "xlsx" | "csv";
40807
+ };
40808
+ header?: never;
40809
+ path?: never;
40810
+ cookie?: never;
40811
+ };
40812
+ requestBody?: never;
40813
+ responses: {
40814
+ /** @description The comisiones workbook (xlsx) */
40815
+ 200: {
40816
+ headers: {
40817
+ /** @description attachment; filename="comisiones-….xlsx" */
40818
+ "Content-Disposition"?: string;
40819
+ [name: string]: unknown;
40820
+ };
40821
+ content: {
40822
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": string;
40823
+ "text/csv": string;
40824
+ };
40825
+ };
40826
+ /** @description Validation error */
40827
+ 400: {
40828
+ headers: {
40829
+ [name: string]: unknown;
40830
+ };
40831
+ content: {
40832
+ "application/json": components["schemas"]["Error"];
40833
+ };
40834
+ };
40835
+ /** @description Unauthorized */
40836
+ 401: {
40837
+ headers: {
40838
+ [name: string]: unknown;
40839
+ };
40840
+ content: {
40841
+ "application/json": components["schemas"]["Error"];
40842
+ };
40843
+ };
40844
+ /** @description Forbidden */
40845
+ 403: {
40846
+ headers: {
40847
+ [name: string]: unknown;
40848
+ };
40849
+ content: {
40850
+ "application/json": components["schemas"]["Error"];
40851
+ };
40852
+ };
40853
+ /** @description Not found */
40854
+ 404: {
40855
+ headers: {
40856
+ [name: string]: unknown;
40857
+ };
40858
+ content: {
40859
+ "application/json": components["schemas"]["Error"];
40860
+ };
40861
+ };
40862
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
40863
+ 409: {
40864
+ headers: {
40865
+ [name: string]: unknown;
40866
+ };
40867
+ content: {
40868
+ "application/json": components["schemas"]["Error"];
40869
+ };
40870
+ };
40871
+ /** @description Rate limited */
40872
+ 429: {
40873
+ headers: {
40874
+ [name: string]: unknown;
40875
+ };
40876
+ content: {
40877
+ "application/json": components["schemas"]["Error"];
40878
+ };
40879
+ };
40880
+ };
40881
+ };
40882
+ put?: never;
40883
+ post?: never;
40884
+ delete?: never;
40885
+ options?: never;
40886
+ head?: never;
40887
+ patch?: never;
40888
+ trace?: never;
40889
+ };
40208
40890
  "/ai-agent-graphs": {
40209
40891
  parameters: {
40210
40892
  query?: never;
@@ -42076,7 +42758,7 @@ interface paths {
42076
42758
  };
42077
42759
  requestBody?: never;
42078
42760
  responses: {
42079
- /** @description The workspace’s rules, evaluation order — vendedor responsable del vehículo, then a consignación intent rule, then an ordinary portal-scoped rule */
42761
+ /** @description The workspace’s rules, evaluation order — responsable del auto, then a consignación intent rule, then an ordinary portal-scoped rule */
42080
42762
  200: {
42081
42763
  headers: {
42082
42764
  [name: string]: unknown;
@@ -42088,7 +42770,7 @@ interface paths {
42088
42770
  * {
42089
42771
  * "id": "5c6f2a10-9b2e-4f7a-8b8b-1a2b3c4d5e6f",
42090
42772
  * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
42091
- * "name": "Vendedor responsable del vehículo",
42773
+ * "name": "Responsable del auto",
42092
42774
  * "enabled": true,
42093
42775
  * "priority": 0,
42094
42776
  * "match_sources": [],
@@ -60876,7 +61558,7 @@ interface paths {
60876
61558
  };
60877
61559
  trace?: never;
60878
61560
  };
60879
- "/clinic/patients/{id}/encounters": {
61561
+ "/clinic/migration/runs": {
60880
61562
  parameters: {
60881
61563
  query?: never;
60882
61564
  header?: never;
@@ -60884,27 +61566,23 @@ interface paths {
60884
61566
  cookie?: never;
60885
61567
  };
60886
61568
  /**
60887
- * Atenciones of one patient, newest first, with their notes
60888
- * @description The «Atenciones» tab. Each atención carries its evoluciones in order, including the amendment chain: an amended note is a NEW row pointing at the one it corrects via `amends_note_id`, and both stay. Voided atenciones are hidden unless `include_voided=true`. Requires `clinic_record:read` AND the per-patient PHI gate. Every call writes a `clinic_record_access_log` row; a call that cannot write its access event fails.
61569
+ * The clinic’s migration runs, newest first
61570
+ * @description The clinic’s migration runs, newest first
60889
61571
  *
60890
- * **Connected apps:** refused with `403 CONNECTED_APP_SENSITIVE_DATA`, whatever scopes they hold — this operation carries a dato sensible (ADR 0106 §4). Only an API key or a personal token of the workspace that holds the scope reaches it.
61572
+ * **Connected apps:** every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, `"M.F. · #1001"` — unless the clinic allowed patient names, with RUT, phone and email masked in free text and `meta.patient_privacy` saying so. Clinical alerts (`flags`) are withheld in both modes, and a non-JSON body (an export, a file) is refused with `403 CONNECTED_APP_SENSITIVE_DATA`.
60891
61573
  */
60892
61574
  get: {
60893
61575
  parameters: {
60894
61576
  query?: {
60895
- page?: number;
60896
61577
  limit?: number;
60897
- include_voided?: "true" | "false";
60898
61578
  };
60899
61579
  header?: never;
60900
- path: {
60901
- id: string;
60902
- };
61580
+ path?: never;
60903
61581
  cookie?: never;
60904
61582
  };
60905
61583
  requestBody?: never;
60906
61584
  responses: {
60907
- /** @description Atenciones */
61585
+ /** @description MigrationRuns */
60908
61586
  200: {
60909
61587
  headers: {
60910
61588
  [name: string]: unknown;
@@ -60913,41 +61591,340 @@ interface paths {
60913
61591
  /**
60914
61592
  * @example {
60915
61593
  * "data": {
60916
- * "data": [
61594
+ * "items": [
60917
61595
  * {
60918
- * "id": "434a1a10-0000-4000-8000-000000000001",
60919
- * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
60920
- * "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
60921
- * "appointment_id": "d93e8eec-0000-4000-8000-000000000001",
60922
- * "professional_id": "18342d1b-0000-4000-8000-000000000001",
60923
- * "location_id": "b1b1b1b1-0000-4000-8000-000000000002",
60924
- * "treatment_plan_id": null,
60925
- * "form_template_id": null,
60926
- * "kind": "control",
60927
- * "status": "open",
60928
- * "starts_at": "2026-09-22T22:21:17.396Z",
60929
- * "ends_at": null,
60930
- * "closed_at": null,
60931
- * "opened_by_user_id": "11111111-0000-4000-8000-000000000001",
60932
- * "closed_by_user_id": null,
60933
- * "voided_reason": null,
60934
- * "author": {
60935
- * "kind": "member",
60936
- * "id": "11111111-0000-4000-8000-000000000001",
60937
- * "name": null,
60938
- * "via": {
60939
- * "kind": "personal_token",
60940
- * "name": "Token personal de la dirección"
60941
- * }
60942
- * },
60943
- * "created_at": "2026-09-22T22:21:17.394Z",
60944
- * "updated_at": "2026-09-22T22:21:17.394Z",
60945
- * "notes": []
61596
+ * "id": "01929a5e-7c10-7d3e-9a41-5b8f2c6d1e07",
61597
+ * "mode": "apply",
61598
+ * "status": "completed",
61599
+ * "status_label": "Completada",
61600
+ * "families": [
61601
+ * "patients",
61602
+ * "appointments"
61603
+ * ],
61604
+ * "started_at": "2026-10-30T23:05:00.000Z",
61605
+ * "finished_at": "2026-10-31T01:42:10.000Z",
61606
+ * "totals": {
61607
+ * "examined": 4213,
61608
+ * "created": 3980,
61609
+ * "unchanged": 190,
61610
+ * "gaps": 43
61611
+ * }
60946
61612
  * }
60947
- * ],
60948
- * "total": 1,
60949
- * "page": 1,
60950
- * "limit": 25
61613
+ * ]
61614
+ * }
61615
+ * }
61616
+ */
61617
+ "application/json": {
61618
+ data?: unknown;
61619
+ meta?: {
61620
+ [key: string]: unknown;
61621
+ };
61622
+ };
61623
+ };
61624
+ };
61625
+ /** @description Validation error */
61626
+ 400: {
61627
+ headers: {
61628
+ [name: string]: unknown;
61629
+ };
61630
+ content: {
61631
+ "application/json": components["schemas"]["Error"];
61632
+ };
61633
+ };
61634
+ /** @description Unauthorized */
61635
+ 401: {
61636
+ headers: {
61637
+ [name: string]: unknown;
61638
+ };
61639
+ content: {
61640
+ "application/json": components["schemas"]["Error"];
61641
+ };
61642
+ };
61643
+ /** @description Forbidden */
61644
+ 403: {
61645
+ headers: {
61646
+ [name: string]: unknown;
61647
+ };
61648
+ content: {
61649
+ "application/json": components["schemas"]["Error"];
61650
+ };
61651
+ };
61652
+ /** @description Not found */
61653
+ 404: {
61654
+ headers: {
61655
+ [name: string]: unknown;
61656
+ };
61657
+ content: {
61658
+ "application/json": components["schemas"]["Error"];
61659
+ };
61660
+ };
61661
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
61662
+ 409: {
61663
+ headers: {
61664
+ [name: string]: unknown;
61665
+ };
61666
+ content: {
61667
+ "application/json": components["schemas"]["Error"];
61668
+ };
61669
+ };
61670
+ /** @description Rate limited */
61671
+ 429: {
61672
+ headers: {
61673
+ [name: string]: unknown;
61674
+ };
61675
+ content: {
61676
+ "application/json": components["schemas"]["Error"];
61677
+ };
61678
+ };
61679
+ };
61680
+ };
61681
+ put?: never;
61682
+ post?: never;
61683
+ delete?: never;
61684
+ options?: never;
61685
+ head?: never;
61686
+ patch?: never;
61687
+ trace?: never;
61688
+ };
61689
+ "/clinic/migration/runs/{id}": {
61690
+ parameters: {
61691
+ query?: never;
61692
+ header?: never;
61693
+ path?: never;
61694
+ cookie?: never;
61695
+ };
61696
+ /**
61697
+ * One migration run: progress per family, gaps by reason
61698
+ * @description Per family: status, phase, counts (examined / created / converted / updated / unchanged / kept_native / collapsed / skipped / gaps), progress against the latest dry-run, vendor requests. The gap summary counts what could not come across by reason, with Spanish labels. Counts and reason codes only — never a patient.
61699
+ *
61700
+ * **Connected apps:** every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, `"M.F. · #1001"` — unless the clinic allowed patient names, with RUT, phone and email masked in free text and `meta.patient_privacy` saying so. Clinical alerts (`flags`) are withheld in both modes, and a non-JSON body (an export, a file) is refused with `403 CONNECTED_APP_SENSITIVE_DATA`.
61701
+ */
61702
+ get: {
61703
+ parameters: {
61704
+ query?: never;
61705
+ header?: never;
61706
+ path: {
61707
+ id: string;
61708
+ };
61709
+ cookie?: never;
61710
+ };
61711
+ requestBody?: never;
61712
+ responses: {
61713
+ /** @description MigrationRun */
61714
+ 200: {
61715
+ headers: {
61716
+ [name: string]: unknown;
61717
+ };
61718
+ content: {
61719
+ /**
61720
+ * @example {
61721
+ * "data": {
61722
+ * "id": "01929a5e-7c10-7d3e-9a41-5b8f2c6d1e07",
61723
+ * "mode": "apply",
61724
+ * "status": "completed",
61725
+ * "status_label": "Completada",
61726
+ * "families": [
61727
+ * {
61728
+ * "family": "patients",
61729
+ * "label": "Fichas administrativas de pacientes (con cargas)",
61730
+ * "status": "done",
61731
+ * "status_label": "Lista",
61732
+ * "reason": null,
61733
+ * "reason_label": null,
61734
+ * "phase": null,
61735
+ * "phase_label": null,
61736
+ * "counts": {
61737
+ * "examined": 1480,
61738
+ * "created": 1402,
61739
+ * "unchanged": 60,
61740
+ * "gaps": 18
61741
+ * },
61742
+ * "progress": {
61743
+ * "examined": 1480,
61744
+ * "expected": 1480
61745
+ * },
61746
+ * "vendor_requests": 31,
61747
+ * "failures": 0,
61748
+ * "started_at": "2026-10-30T23:05:02.000Z",
61749
+ * "finished_at": "2026-10-30T23:31:40.000Z"
61750
+ * }
61751
+ * ],
61752
+ * "totals": {
61753
+ * "examined": 1480,
61754
+ * "created": 1402,
61755
+ * "unchanged": 60,
61756
+ * "gaps": 18
61757
+ * },
61758
+ * "gaps": [
61759
+ * {
61760
+ * "family": "patients",
61761
+ * "reason": "native_rut_match",
61762
+ * "reason_label": "Ya existe en Vitrina una ficha creada aquí con el mismo RUT: no se duplicó ni se fusionó.",
61763
+ * "count": 18
61764
+ * }
61765
+ * ],
61766
+ * "history_from": "2021-01-01",
61767
+ * "window_ends_at": "2026-11-01T21:00:00.000Z",
61768
+ * "started_at": "2026-10-30T23:05:00.000Z",
61769
+ * "finished_at": "2026-10-30T23:31:40.000Z",
61770
+ * "last_progress_at": "2026-10-30T23:31:40.000Z",
61771
+ * "job_deleted_at": "2026-10-30T23:31:41.000Z",
61772
+ * "instruction": {
61773
+ * "version": "clinic-migration-instruction/2026-09-28",
61774
+ * "sha256": "b1946ac92492d2347c6235b4d2611184b1946ac92492d2347c6235b4d2611184",
61775
+ * "text": "Instruyo a Vitrina copiar desde Dentalink las fichas administrativas de pacientes …",
61776
+ * "instructed_by_user_id": "20000000-0000-4000-8000-000000000001",
61777
+ * "instructed_at": "2026-10-30T23:04:40.000Z",
61778
+ * "document_reference": null
61779
+ * },
61780
+ * "error": null
61781
+ * }
61782
+ * }
61783
+ */
61784
+ "application/json": {
61785
+ data?: unknown;
61786
+ meta?: {
61787
+ [key: string]: unknown;
61788
+ };
61789
+ };
61790
+ };
61791
+ };
61792
+ /** @description Validation error */
61793
+ 400: {
61794
+ headers: {
61795
+ [name: string]: unknown;
61796
+ };
61797
+ content: {
61798
+ "application/json": components["schemas"]["Error"];
61799
+ };
61800
+ };
61801
+ /** @description Unauthorized */
61802
+ 401: {
61803
+ headers: {
61804
+ [name: string]: unknown;
61805
+ };
61806
+ content: {
61807
+ "application/json": components["schemas"]["Error"];
61808
+ };
61809
+ };
61810
+ /** @description Forbidden */
61811
+ 403: {
61812
+ headers: {
61813
+ [name: string]: unknown;
61814
+ };
61815
+ content: {
61816
+ "application/json": components["schemas"]["Error"];
61817
+ };
61818
+ };
61819
+ /** @description Not found */
61820
+ 404: {
61821
+ headers: {
61822
+ [name: string]: unknown;
61823
+ };
61824
+ content: {
61825
+ "application/json": components["schemas"]["Error"];
61826
+ };
61827
+ };
61828
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
61829
+ 409: {
61830
+ headers: {
61831
+ [name: string]: unknown;
61832
+ };
61833
+ content: {
61834
+ "application/json": components["schemas"]["Error"];
61835
+ };
61836
+ };
61837
+ /** @description Rate limited */
61838
+ 429: {
61839
+ headers: {
61840
+ [name: string]: unknown;
61841
+ };
61842
+ content: {
61843
+ "application/json": components["schemas"]["Error"];
61844
+ };
61845
+ };
61846
+ };
61847
+ };
61848
+ put?: never;
61849
+ post?: never;
61850
+ delete?: never;
61851
+ options?: never;
61852
+ head?: never;
61853
+ patch?: never;
61854
+ trace?: never;
61855
+ };
61856
+ "/clinic/patients/{id}/encounters": {
61857
+ parameters: {
61858
+ query?: never;
61859
+ header?: never;
61860
+ path?: never;
61861
+ cookie?: never;
61862
+ };
61863
+ /**
61864
+ * Atenciones of one patient, newest first, with their notes
61865
+ * @description The «Atenciones» tab. Each atención carries its evoluciones in order, including the amendment chain: an amended note is a NEW row pointing at the one it corrects via `amends_note_id`, and both stay. Voided atenciones are hidden unless `include_voided=true`. Requires `clinic_record:read` AND the per-patient PHI gate. Every call writes a `clinic_record_access_log` row; a call that cannot write its access event fails.
61866
+ *
61867
+ * **Connected apps:** refused with `403 CONNECTED_APP_SENSITIVE_DATA`, whatever scopes they hold — this operation carries a dato sensible (ADR 0106 §4). Only an API key or a personal token of the workspace that holds the scope reaches it.
61868
+ */
61869
+ get: {
61870
+ parameters: {
61871
+ query?: {
61872
+ page?: number;
61873
+ limit?: number;
61874
+ include_voided?: "true" | "false";
61875
+ };
61876
+ header?: never;
61877
+ path: {
61878
+ id: string;
61879
+ };
61880
+ cookie?: never;
61881
+ };
61882
+ requestBody?: never;
61883
+ responses: {
61884
+ /** @description Atenciones */
61885
+ 200: {
61886
+ headers: {
61887
+ [name: string]: unknown;
61888
+ };
61889
+ content: {
61890
+ /**
61891
+ * @example {
61892
+ * "data": {
61893
+ * "data": [
61894
+ * {
61895
+ * "id": "434a1a10-0000-4000-8000-000000000001",
61896
+ * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
61897
+ * "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
61898
+ * "appointment_id": "d93e8eec-0000-4000-8000-000000000001",
61899
+ * "professional_id": "18342d1b-0000-4000-8000-000000000001",
61900
+ * "location_id": "b1b1b1b1-0000-4000-8000-000000000002",
61901
+ * "treatment_plan_id": null,
61902
+ * "form_template_id": null,
61903
+ * "kind": "control",
61904
+ * "status": "open",
61905
+ * "starts_at": "2026-09-22T22:21:17.396Z",
61906
+ * "ends_at": null,
61907
+ * "closed_at": null,
61908
+ * "opened_by_user_id": "11111111-0000-4000-8000-000000000001",
61909
+ * "closed_by_user_id": null,
61910
+ * "voided_reason": null,
61911
+ * "author": {
61912
+ * "kind": "member",
61913
+ * "id": "11111111-0000-4000-8000-000000000001",
61914
+ * "name": null,
61915
+ * "via": {
61916
+ * "kind": "personal_token",
61917
+ * "name": "Token personal de la dirección"
61918
+ * }
61919
+ * },
61920
+ * "created_at": "2026-09-22T22:21:17.394Z",
61921
+ * "updated_at": "2026-09-22T22:21:17.394Z",
61922
+ * "notes": []
61923
+ * }
61924
+ * ],
61925
+ * "total": 1,
61926
+ * "page": 1,
61927
+ * "limit": 25
60951
61928
  * }
60952
61929
  * }
60953
61930
  */
@@ -71061,6 +72038,263 @@ interface paths {
71061
72038
  patch?: never;
71062
72039
  trace?: never;
71063
72040
  };
72041
+ "/clinic/insights/resultados": {
72042
+ parameters: {
72043
+ query?: never;
72044
+ header?: never;
72045
+ path?: never;
72046
+ cookie?: never;
72047
+ };
72048
+ /**
72049
+ * «Tu agenda con Vitrina»: what the AI did for the diary
72050
+ * @description One canonical read of what Vitrina's agent did for the clinic's agenda, aggregates only (never a patient, cita or conversation id). A cita is «agendada por Vitrina» when the agent booked it in a conversation (`source = 'agent'` and no public booking page); the window is on the day the cita HAPPENS (`starts_at`), blocks and holds out. Blocks: `bookings` (count and share of the agenda, with the previous period of the same length); `money` (the value of those citas — pipeline — and the CASH their patients paid in the period from the day Vitrina booked them, read from the revenue mirror when it is on, else from the native ledger; `null` with `withheld: true` for a caller without `clinic_money:read`); `out_of_hours` (bookings made while the workspace was closed per its business hours, plus a weekday × hour heatmap; `null` when no hours are configured); `autonomy` (bookings with no team message in the conversation, from the patient's first message of the 7 days before); `time_to_book` (median and p95, first patient message → booking); `hours_returned` (AI bookings × 10 minutes, a stated rule); `recovery` (no-shows over known attendance, and no-shows / cancellations the same patient booked again within 30 days, with how many of those Vitrina booked); `confirmation` (attendance of confirmed vs unconfirmed citas, the `confirmaciones` report's own figures); `ads` (cost per cita agendada / asistida / paciente que pagó = the Ads overview's spend ÷ its counts for the same dates; `not_active` without Vitrina Ads); `reminders` (reminders that did not go out, by cause). Every block carries a printable `rule`; every rate is `null` — never 0 — without a denominator, and measured figures carry `measured` / `unknown` counts. Requires `clinic:read`. Accepts `from` / `to` (bare `YYYY-MM-DD`, `to` inclusive; default the 90 days ending today in the clinic's zone) and `location_id`.
72051
+ *
72052
+ * **Connected apps:** every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, `"M.F. · #1001"` — unless the clinic allowed patient names, with RUT, phone and email masked in free text and `meta.patient_privacy` saying so. Clinical alerts (`flags`) are withheld in both modes, and a non-JSON body (an export, a file) is refused with `403 CONNECTED_APP_SENSITIVE_DATA`.
72053
+ */
72054
+ get: {
72055
+ parameters: {
72056
+ query?: {
72057
+ /** @description First day of the window (by the day the cita happens), inclusive. Defaults to 90 days before `to`. */
72058
+ from?: string;
72059
+ /** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
72060
+ to?: string;
72061
+ /** @description One sucursal. Omit for all of them. */
72062
+ location_id?: string;
72063
+ };
72064
+ header?: never;
72065
+ path?: never;
72066
+ cookie?: never;
72067
+ };
72068
+ requestBody?: never;
72069
+ responses: {
72070
+ /** @description Tu agenda con Vitrina */
72071
+ 200: {
72072
+ headers: {
72073
+ [name: string]: unknown;
72074
+ };
72075
+ content: {
72076
+ /**
72077
+ * @example {
72078
+ * "data": {
72079
+ * "from": "2026-07-01",
72080
+ * "to": "2026-09-28",
72081
+ * "timezone": "America/Santiago",
72082
+ * "location_id": null,
72083
+ * "family": "clinic",
72084
+ * "previous_period": {
72085
+ * "from": "2026-04-02",
72086
+ * "to": "2026-06-30"
72087
+ * },
72088
+ * "bookings": {
72089
+ * "ai": 286,
72090
+ * "agenda_total": 2011,
72091
+ * "share_pct": 14.2,
72092
+ * "previous": {
72093
+ * "ai": 240,
72094
+ * "agenda_total": 1950,
72095
+ * "share_pct": 12.3
72096
+ * },
72097
+ * "rule": "Citas del período (por la fecha de la cita) que agendó el asistente de Vitrina en una conversación, ÷ todas las citas del período."
72098
+ * },
72099
+ * "money": {
72100
+ * "applies": true,
72101
+ * "withheld": false,
72102
+ * "booked_clp": 11400000,
72103
+ * "booked_priced": 271,
72104
+ * "booked_unpriced": 15,
72105
+ * "agenda_clp": 96000000,
72106
+ * "clp_share_pct": 11.9,
72107
+ * "paid_clp": 7250000,
72108
+ * "paid_patients": 164,
72109
+ * "unlinked": 4,
72110
+ * "regime": "mirror",
72111
+ * "previous": {
72112
+ * "booked_clp": 9800000,
72113
+ * "paid_clp": 6100000
72114
+ * },
72115
+ * "rule_booked": "Valor de las citas que agendó Vitrina: el precio de sus prestaciones, o el del catálogo. Es lo agendado, no lo cobrado.",
72116
+ * "rule_paid": "Pagos recibidos en el período por los pacientes que Vitrina agendó, desde el día en que los agendó."
72117
+ * },
72118
+ * "out_of_hours": {
72119
+ * "configured": true,
72120
+ * "count": 111,
72121
+ * "pct": 38.8,
72122
+ * "previous_pct": 36.1,
72123
+ * "heatmap": [
72124
+ * {
72125
+ * "weekday": 1,
72126
+ * "hour": 21,
72127
+ * "count": 9
72128
+ * },
72129
+ * {
72130
+ * "weekday": 6,
72131
+ * "hour": 11,
72132
+ * "count": 14
72133
+ * }
72134
+ * ],
72135
+ * "rule": "Citas que Vitrina agendó mientras tu negocio estaba cerrado, según tu horario de atención (incluye feriados)."
72136
+ * },
72137
+ * "autonomy": {
72138
+ * "no_human": 158,
72139
+ * "pct": 56.6,
72140
+ * "measured": 279,
72141
+ * "unknown": 7,
72142
+ * "previous_pct": 52,
72143
+ * "rule": "Citas de Vitrina en las que nadie de tu equipo escribió en la conversación antes de agendar."
72144
+ * },
72145
+ * "time_to_book": {
72146
+ * "median_seconds": 734,
72147
+ * "p95_seconds": 80100,
72148
+ * "p95_phrase": "5 de cada 100 personas tardan más de 22 h 15 min en quedar agendadas.",
72149
+ * "measured": 279,
72150
+ * "unknown": 7,
72151
+ * "previous_median_seconds": 910,
72152
+ * "rule": "Tiempo desde el primer mensaje del paciente hasta que su cita quedó agendada (la mediana)."
72153
+ * },
72154
+ * "hours_returned": {
72155
+ * "minutes_per_booking": 10,
72156
+ * "hours": 47.7,
72157
+ * "rule": "Cada cita que agenda Vitrina ahorra 10 minutos de responder y agendar a mano."
72158
+ * },
72159
+ * "recovery": {
72160
+ * "window_days": 30,
72161
+ * "known_attendance": 1063,
72162
+ * "unknown_attendance": 21,
72163
+ * "no_show_pct": 10.2,
72164
+ * "no_show": {
72165
+ * "count": 108,
72166
+ * "recovered": 37,
72167
+ * "recovered_via_vitrina": 17,
72168
+ * "recovered_pct": 34.6,
72169
+ * "via_vitrina_pct": 15.9,
72170
+ * "pending": 12,
72171
+ * "unlinked": 1
72172
+ * },
72173
+ * "cancelled": {
72174
+ * "count": 240,
72175
+ * "recovered": 26,
72176
+ * "recovered_via_vitrina": 11,
72177
+ * "recovered_pct": 10.8,
72178
+ * "via_vitrina_pct": 4.6,
72179
+ * "pending": 18,
72180
+ * "unlinked": 0
72181
+ * },
72182
+ * "rule_no_show": "Citas pasadas marcadas como «no asistió» ÷ citas con asistencia conocida (asistió + no asistió).",
72183
+ * "rule_recovered": "Una cita perdida se recupera cuando el mismo paciente agenda otra dentro de 30 días."
72184
+ * },
72185
+ * "confirmation": {
72186
+ * "applies": true,
72187
+ * "confirmed_attendance_pct": 93.1,
72188
+ * "unconfirmed_attendance_pct": 78.4,
72189
+ * "confirmed_closed": 610,
72190
+ * "unconfirmed_closed": 212,
72191
+ * "rule": "Asistencia de las citas cuyo paciente confirmó el recordatorio, frente a las que nunca respondieron."
72192
+ * },
72193
+ * "ads": {
72194
+ * "state": "active",
72195
+ * "spend_clp": 1648000,
72196
+ * "booked": 58,
72197
+ * "attended": 41,
72198
+ * "paid": 22,
72199
+ * "cost_per_booked": 28414,
72200
+ * "cost_per_attended": 40195,
72201
+ * "cost_per_paid": 74909,
72202
+ * "rule": "Inversión en anuncios del período ÷ citas agendadas, asistidas y pacientes que pagaron por primera vez, según Vitrina Ads para las mismas fechas."
72203
+ * },
72204
+ * "reminders": {
72205
+ * "applies": true,
72206
+ * "sent": 721,
72207
+ * "failed": 120,
72208
+ * "failed_pct": 14.3,
72209
+ * "by_cause": [
72210
+ * {
72211
+ * "cause": "no_whatsapp",
72212
+ * "count": 61
72213
+ * },
72214
+ * {
72215
+ * "cause": "no_phone",
72216
+ * "count": 38
72217
+ * },
72218
+ * {
72219
+ * "cause": "meta_payment_block",
72220
+ * "count": 21
72221
+ * }
72222
+ * ],
72223
+ * "rule": "Recordatorios de citas del período que no salieron, agrupados por la causa que registró el envío."
72224
+ * },
72225
+ * "truncated": false
72226
+ * }
72227
+ * }
72228
+ */
72229
+ "application/json": {
72230
+ data: components["schemas"]["AgendaResults"];
72231
+ };
72232
+ };
72233
+ };
72234
+ /** @description Validation error */
72235
+ 400: {
72236
+ headers: {
72237
+ [name: string]: unknown;
72238
+ };
72239
+ content: {
72240
+ "application/json": components["schemas"]["Error"];
72241
+ };
72242
+ };
72243
+ /** @description Unauthorized */
72244
+ 401: {
72245
+ headers: {
72246
+ [name: string]: unknown;
72247
+ };
72248
+ content: {
72249
+ "application/json": components["schemas"]["Error"];
72250
+ };
72251
+ };
72252
+ /** @description Forbidden */
72253
+ 403: {
72254
+ headers: {
72255
+ [name: string]: unknown;
72256
+ };
72257
+ content: {
72258
+ "application/json": components["schemas"]["Error"];
72259
+ };
72260
+ };
72261
+ /** @description Not found */
72262
+ 404: {
72263
+ headers: {
72264
+ [name: string]: unknown;
72265
+ };
72266
+ content: {
72267
+ "application/json": components["schemas"]["Error"];
72268
+ };
72269
+ };
72270
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
72271
+ 409: {
72272
+ headers: {
72273
+ [name: string]: unknown;
72274
+ };
72275
+ content: {
72276
+ "application/json": components["schemas"]["Error"];
72277
+ };
72278
+ };
72279
+ /** @description Rate limited */
72280
+ 429: {
72281
+ headers: {
72282
+ [name: string]: unknown;
72283
+ };
72284
+ content: {
72285
+ "application/json": components["schemas"]["Error"];
72286
+ };
72287
+ };
72288
+ };
72289
+ };
72290
+ put?: never;
72291
+ post?: never;
72292
+ delete?: never;
72293
+ options?: never;
72294
+ head?: never;
72295
+ patch?: never;
72296
+ trace?: never;
72297
+ };
71064
72298
  "/clinic/insights/comercial": {
71065
72299
  parameters: {
71066
72300
  query?: never;
@@ -76995,6 +78229,8 @@ interface paths {
76995
78229
  * @description Answers the question the agent and the test-drive flow actually ask: is this car ours to hand over? Returns the ACTIVE contract (or null) plus a `not_on_lot` flag.
76996
78230
  *
76997
78231
  * Use this rather than filtering the list by `vehicle_id`: a vehicle can have several historical contracts and only ever one active, and this endpoint is the one that resolves that.
78232
+ *
78233
+ * `mandato` is the active contract’s mandato (ADR 0114 §5): `sin_emitir` — approving the sale of this car is refused until it is emitted; `sin_firmar` — emitted, but no signed copy was filed in the car’s expediente (the car shows an alert; nothing is blocked); `firmado`. `null` when there is no active contract.
76998
78234
  */
76999
78235
  get: {
77000
78236
  parameters: {
@@ -77016,6 +78252,12 @@ interface paths {
77016
78252
  /**
77017
78253
  * @example {
77018
78254
  * "data": {
78255
+ * "vehicleId": "e1e1e1e1-0000-4000-8000-000000000001",
78256
+ * "tenencia": "consignacion",
78257
+ * "tenenciaSource": "document",
78258
+ * "hasActiveContract": true,
78259
+ * "modalidad": "en_local",
78260
+ * "notOnLot": false,
77019
78261
  * "contract": {
77020
78262
  * "id": "d7d7d7d7-0000-4000-8000-000000000001",
77021
78263
  * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
@@ -77035,129 +78277,134 @@ interface paths {
77035
78277
  * "sale_iva_regime": "exento",
77036
78278
  * "not_on_lot": false
77037
78279
  * },
77038
- * "not_on_lot": false
77039
- * }
77040
- * }
77041
- */
77042
- "application/json": {
77043
- data?: unknown;
77044
- meta?: {
77045
- [key: string]: unknown;
77046
- };
77047
- };
77048
- };
77049
- };
77050
- /** @description Validation error */
77051
- 400: {
77052
- headers: {
77053
- [name: string]: unknown;
77054
- };
77055
- content: {
77056
- "application/json": components["schemas"]["Error"];
77057
- };
77058
- };
77059
- /** @description Unauthorized */
77060
- 401: {
77061
- headers: {
77062
- [name: string]: unknown;
77063
- };
77064
- content: {
77065
- "application/json": components["schemas"]["Error"];
77066
- };
77067
- };
77068
- /** @description Forbidden */
77069
- 403: {
77070
- headers: {
77071
- [name: string]: unknown;
77072
- };
77073
- content: {
77074
- "application/json": components["schemas"]["Error"];
77075
- };
77076
- };
77077
- /** @description Not found */
77078
- 404: {
77079
- headers: {
77080
- [name: string]: unknown;
77081
- };
77082
- content: {
77083
- "application/json": components["schemas"]["Error"];
77084
- };
77085
- };
77086
- /** @description Conflict (incl. Idempotency-Key reuse with different body) */
77087
- 409: {
77088
- headers: {
77089
- [name: string]: unknown;
77090
- };
77091
- content: {
77092
- "application/json": components["schemas"]["Error"];
77093
- };
77094
- };
77095
- /** @description Rate limited */
77096
- 429: {
77097
- headers: {
77098
- [name: string]: unknown;
77099
- };
77100
- content: {
77101
- "application/json": components["schemas"]["Error"];
77102
- };
77103
- };
77104
- };
77105
- };
77106
- put?: never;
77107
- post?: never;
77108
- delete?: never;
77109
- options?: never;
77110
- head?: never;
77111
- patch?: never;
77112
- trace?: never;
77113
- };
77114
- "/consignments/{id}": {
77115
- parameters: {
77116
- query?: never;
77117
- header?: never;
77118
- path?: never;
77119
- cookie?: never;
77120
- };
77121
- /**
77122
- * Fetch one contract
77123
- * @description The contract as stored, whatever its state.
77124
- */
77125
- get: {
77126
- parameters: {
77127
- query?: never;
77128
- header?: never;
77129
- path: {
77130
- id: string;
77131
- };
77132
- cookie?: never;
77133
- };
77134
- requestBody?: never;
77135
- responses: {
77136
- /** @description The contract */
77137
- 200: {
77138
- headers: {
77139
- [name: string]: unknown;
77140
- };
77141
- content: {
77142
- /**
77143
- * @example {
77144
- * "data": {
77145
- * "id": "d7d7d7d7-0000-4000-8000-000000000001",
77146
- * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
77147
- * "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
77148
- * "dueno_contact_id": "22222222-0000-4000-8000-000000000004",
77149
- * "modalidad": "en_local",
77150
- * "contract_structure": "mandato_con_representacion",
77151
- * "comision_type": "percentage",
77152
- * "comision_value": 10,
77153
- * "minimo_clp": 8000000,
77154
- * "vencimiento": "2026-12-31",
77155
- * "estado": "activo",
77156
- * "vencimiento_reminded_at": null,
77157
- * "liquidacion_due_notified_at": null,
77158
- * "created_at": "2026-08-20T10:00:00.000Z",
77159
- * "updated_at": "2026-08-20T10:00:00.000Z",
77160
- * "sale_iva_regime": "exento",
78280
+ * "mandato": {
78281
+ * "contractId": "d7d7d7d7-0000-4000-8000-000000000001",
78282
+ * "estado": "sin_firmar",
78283
+ * "emittedAt": "2026-09-10T14:00:00.000Z",
78284
+ * "signedAt": null
78285
+ * }
78286
+ * }
78287
+ * }
78288
+ */
78289
+ "application/json": {
78290
+ data?: unknown;
78291
+ meta?: {
78292
+ [key: string]: unknown;
78293
+ };
78294
+ };
78295
+ };
78296
+ };
78297
+ /** @description Validation error */
78298
+ 400: {
78299
+ headers: {
78300
+ [name: string]: unknown;
78301
+ };
78302
+ content: {
78303
+ "application/json": components["schemas"]["Error"];
78304
+ };
78305
+ };
78306
+ /** @description Unauthorized */
78307
+ 401: {
78308
+ headers: {
78309
+ [name: string]: unknown;
78310
+ };
78311
+ content: {
78312
+ "application/json": components["schemas"]["Error"];
78313
+ };
78314
+ };
78315
+ /** @description Forbidden */
78316
+ 403: {
78317
+ headers: {
78318
+ [name: string]: unknown;
78319
+ };
78320
+ content: {
78321
+ "application/json": components["schemas"]["Error"];
78322
+ };
78323
+ };
78324
+ /** @description Not found */
78325
+ 404: {
78326
+ headers: {
78327
+ [name: string]: unknown;
78328
+ };
78329
+ content: {
78330
+ "application/json": components["schemas"]["Error"];
78331
+ };
78332
+ };
78333
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
78334
+ 409: {
78335
+ headers: {
78336
+ [name: string]: unknown;
78337
+ };
78338
+ content: {
78339
+ "application/json": components["schemas"]["Error"];
78340
+ };
78341
+ };
78342
+ /** @description Rate limited */
78343
+ 429: {
78344
+ headers: {
78345
+ [name: string]: unknown;
78346
+ };
78347
+ content: {
78348
+ "application/json": components["schemas"]["Error"];
78349
+ };
78350
+ };
78351
+ };
78352
+ };
78353
+ put?: never;
78354
+ post?: never;
78355
+ delete?: never;
78356
+ options?: never;
78357
+ head?: never;
78358
+ patch?: never;
78359
+ trace?: never;
78360
+ };
78361
+ "/consignments/{id}": {
78362
+ parameters: {
78363
+ query?: never;
78364
+ header?: never;
78365
+ path?: never;
78366
+ cookie?: never;
78367
+ };
78368
+ /**
78369
+ * Fetch one contract
78370
+ * @description The contract as stored, whatever its state.
78371
+ */
78372
+ get: {
78373
+ parameters: {
78374
+ query?: never;
78375
+ header?: never;
78376
+ path: {
78377
+ id: string;
78378
+ };
78379
+ cookie?: never;
78380
+ };
78381
+ requestBody?: never;
78382
+ responses: {
78383
+ /** @description The contract */
78384
+ 200: {
78385
+ headers: {
78386
+ [name: string]: unknown;
78387
+ };
78388
+ content: {
78389
+ /**
78390
+ * @example {
78391
+ * "data": {
78392
+ * "id": "d7d7d7d7-0000-4000-8000-000000000001",
78393
+ * "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
78394
+ * "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
78395
+ * "dueno_contact_id": "22222222-0000-4000-8000-000000000004",
78396
+ * "modalidad": "en_local",
78397
+ * "contract_structure": "mandato_con_representacion",
78398
+ * "comision_type": "percentage",
78399
+ * "comision_value": 10,
78400
+ * "minimo_clp": 8000000,
78401
+ * "vencimiento": "2026-12-31",
78402
+ * "estado": "activo",
78403
+ * "vencimiento_reminded_at": null,
78404
+ * "liquidacion_due_notified_at": null,
78405
+ * "created_at": "2026-08-20T10:00:00.000Z",
78406
+ * "updated_at": "2026-08-20T10:00:00.000Z",
78407
+ * "sale_iva_regime": "exento",
77161
78408
  * "not_on_lot": false
77162
78409
  * }
77163
78410
  * }
@@ -77512,6 +78759,8 @@ interface paths {
77512
78759
  * Sell the car and settle with the owner
77513
78760
  * @description One atomic action doing two things: moves the contract to `vendido`, and produces the **Liquidación** — sale price minus commission equals the amount owed to the owner, plus the payment record. Requires `amount_venta_clp`; `paid_at` records when the owner was actually paid.
77514
78761
  *
78762
+ * **The payout is described in full or refused (400)**: `payout_method` (transferencia, vale_vista or cheque), `payout_bank`, `payout_account` (the cuenta de destino — only its last four digits are stored and returned as `payout_account_last4`), `payout_operation_number` and `payout_paid_by` («pagado por», an active member of the workspace). All of them print on the liquidación with the payment and registration dates.
78763
+ *
77515
78764
  * Legal only from `activo`; anything else is a 409. Answers 201 with the contract and the Liquidación.
77516
78765
  *
77517
78766
  * It does NOT close the vehicle’s side — the estadía close belongs to the vehicle lifecycle, so mark the vehicle sold separately.
@@ -77533,13 +78782,34 @@ interface paths {
77533
78782
  /**
77534
78783
  * @example {
77535
78784
  * "amount_venta_clp": 8900000,
77536
- * "paid_at": "2026-09-18T15:00:00.000Z"
78785
+ * "paid_at": "2026-09-18T15:00:00.000Z",
78786
+ * "payout_method": "transferencia",
78787
+ * "payout_bank": "Banco de Chile",
78788
+ * "payout_account": "00-123-45678-21",
78789
+ * "payout_operation_number": "99887766",
78790
+ * "payout_paid_by": "11111111-0000-4000-8000-000000000001"
77537
78791
  * }
77538
78792
  */
77539
78793
  "application/json": {
77540
78794
  amount_venta_clp: number;
77541
78795
  /** Format: date-time */
77542
78796
  paid_at?: string;
78797
+ /**
78798
+ * @description Medio de pago al consignante: `transferencia`, `vale_vista` o `cheque`.
78799
+ * @enum {string}
78800
+ */
78801
+ payout_method: "transferencia" | "vale_vista" | "cheque";
78802
+ /** @description Banco por el que se pagó. */
78803
+ payout_bank: string;
78804
+ /** @description Cuenta de destino. Solo se guardan sus últimos 4 dígitos (`payout_account_last4`), que es lo que muestran la app y la liquidación. */
78805
+ payout_account: string;
78806
+ /** @description Número de operación del pago. */
78807
+ payout_operation_number: string;
78808
+ /**
78809
+ * Format: uuid
78810
+ * @description «Pagado por»: id de usuario de un miembro activo del equipo.
78811
+ */
78812
+ payout_paid_by: string;
77543
78813
  };
77544
78814
  };
77545
78815
  };
@@ -77587,6 +78857,12 @@ interface paths {
77587
78857
  * "deducciones_clp": 0,
77588
78858
  * "retiro_motivo": null,
77589
78859
  * "retiro_by": null,
78860
+ * "payout_method": "transferencia",
78861
+ * "payout_bank": "Banco de Chile",
78862
+ * "payout_account_last4": "5821",
78863
+ * "payout_operation_number": "99887766",
78864
+ * "payout_paid_by": "11111111-0000-4000-8000-000000000001",
78865
+ * "payout_paid_by_name": "Ana Pérez",
77590
78866
  * "paid_at": "2026-09-18T15:00:00.000Z",
77591
78867
  * "created_at": "2026-09-18T15:00:05.000Z",
77592
78868
  * "updated_at": "2026-09-18T15:00:05.000Z"
@@ -77671,6 +78947,8 @@ interface paths {
77671
78947
  /**
77672
78948
  * Fetch the settlement record
77673
78949
  * @description The persisted Liquidación for a contract. It only exists once the contract has been sold — this is a read of a record, not a projection computed on demand, so the figures are what was agreed at settlement even if the terms changed afterwards.
78950
+ *
78951
+ * It carries how the owner was paid (`payout_*`, with `payout_paid_by_name` resolved for display). On a liquidación registered before the payout fields were required they are all `null`: nothing reconstructs them, and the app shows them as not registered.
77674
78952
  */
77675
78953
  get: {
77676
78954
  parameters: {
@@ -77706,6 +78984,12 @@ interface paths {
77706
78984
  * "deducciones_clp": 0,
77707
78985
  * "retiro_motivo": null,
77708
78986
  * "retiro_by": null,
78987
+ * "payout_method": "transferencia",
78988
+ * "payout_bank": "Banco de Chile",
78989
+ * "payout_account_last4": "5821",
78990
+ * "payout_operation_number": "99887766",
78991
+ * "payout_paid_by": "11111111-0000-4000-8000-000000000001",
78992
+ * "payout_paid_by_name": "Ana Pérez",
77709
78993
  * "paid_at": "2026-09-18T15:00:00.000Z",
77710
78994
  * "created_at": "2026-09-18T15:00:05.000Z",
77711
78995
  * "updated_at": "2026-09-18T15:00:05.000Z"
@@ -77832,6 +79116,7 @@ interface paths {
77832
79116
  active?: boolean | null;
77833
79117
  filtered?: boolean | null;
77834
79118
  aiReplied?: boolean | null;
79119
+ fromAd?: boolean | null;
77835
79120
  sort?: "created_at" | "updated_at" | "last_message_date";
77836
79121
  order?: "asc" | "desc";
77837
79122
  include?: "counts";
@@ -79622,7 +80907,7 @@ interface paths {
79622
80907
  "application/json": components["schemas"]["OutboundVerdictError"];
79623
80908
  };
79624
80909
  };
79625
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
80910
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
79626
80911
  422: {
79627
80912
  headers: {
79628
80913
  [name: string]: unknown;
@@ -79888,7 +81173,7 @@ interface paths {
79888
81173
  };
79889
81174
  /**
79890
81175
  * List pending scheduled sends
79891
- * @description The replies waiting to fire on this conversation — PENDING ones only: a scheduled message that has gone out, been cancelled or been stopped by the política de envíos at fire time leaves this list. `policy_acknowledged` records the Advertencias the author went ahead over when they scheduled it; those are not re-asked at fire time, a Bloqueo still is.
81176
+ * @description The replies waiting to fire on this conversation, plus the ones that FAILED in the last 7 days (`status: failed`), one per send. A failed row carries `failure: { code, label }`: `code` is one of `copy_refused`, `policy_blocked`, `conversation_missing`, `delivery_failed` or `not_sent`, and `label` is a Spanish sentence to show as is; the raw error is never exposed. `failure` is null on a pending row. One that has gone out, was cancelled or was dismissed leaves this list. `policy_acknowledged` records the Advertencias the author went ahead over when they scheduled it; those are not re-asked at fire time, a Bloqueo still is.
79892
81177
  */
79893
81178
  get: {
79894
81179
  parameters: {
@@ -79921,13 +81206,19 @@ interface paths {
79921
81206
  * "bcc": [],
79922
81207
  * "send_at": "2026-09-23T13:00:00+00:00",
79923
81208
  * "status": "scheduled",
79924
- * "error": null,
79925
- * "message_id": null,
79926
- * "policy_acknowledged": [
79927
- * "conversation_human_owned"
79928
- * ],
79929
- * "created_at": "2026-09-22T11:09:04.112Z",
79930
- * "updated_at": "2026-09-22T11:09:04.112Z"
81209
+ * "failure": null,
81210
+ * "created_at": "2026-09-22T11:09:04.112Z"
81211
+ * },
81212
+ * {
81213
+ * "id": "44444444-0000-4000-8000-00000000b002",
81214
+ * "content": "Adjunto la cotización que me pediste.",
81215
+ * "send_at": "2026-09-22T15:00:00+00:00",
81216
+ * "status": "failed",
81217
+ * "failure": {
81218
+ * "code": "copy_refused",
81219
+ * "label": "Una dirección en copia ya no puede recibir correos (se dio de baja, rebotó o marcó spam). Quítala de cc/bcc y vuelve a enviarlo."
81220
+ * },
81221
+ * "created_at": "2026-09-22T10:02:11.004Z"
79931
81222
  * }
79932
81223
  * ]
79933
81224
  * }
@@ -80016,7 +81307,7 @@ interface paths {
80016
81307
  post?: never;
80017
81308
  /**
80018
81309
  * Cancel a scheduled send
80019
- * @description The reply never goes out and the row is gone — there is no un-cancel, rescheduling means composing it again. A message that already fired (or was already cancelled) is a 404.
81310
+ * @description The reply never goes out and the row is gone — there is no un-cancel, rescheduling means composing it again. On a FAILED row it dismisses it: the row leaves the list. A message that already went out (or was already cancelled or dismissed) is a 404.
80020
81311
  */
80021
81312
  delete: {
80022
81313
  parameters: {
@@ -80253,7 +81544,7 @@ interface paths {
80253
81544
  "application/json": components["schemas"]["OutboundVerdictError"];
80254
81545
  };
80255
81546
  };
80256
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
81547
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
80257
81548
  422: {
80258
81549
  headers: {
80259
81550
  [name: string]: unknown;
@@ -80440,7 +81731,7 @@ interface paths {
80440
81731
  "application/json": components["schemas"]["OutboundVerdictError"];
80441
81732
  };
80442
81733
  };
80443
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
81734
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
80444
81735
  422: {
80445
81736
  headers: {
80446
81737
  [name: string]: unknown;
@@ -80754,7 +82045,7 @@ interface paths {
80754
82045
  "application/json": components["schemas"]["OutboundVerdictError"];
80755
82046
  };
80756
82047
  };
80757
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
82048
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
80758
82049
  422: {
80759
82050
  headers: {
80760
82051
  [name: string]: unknown;
@@ -80931,7 +82222,7 @@ interface paths {
80931
82222
  "application/json": components["schemas"]["OutboundVerdictError"];
80932
82223
  };
80933
82224
  };
80934
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
82225
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
80935
82226
  422: {
80936
82227
  headers: {
80937
82228
  [name: string]: unknown;
@@ -81102,7 +82393,7 @@ interface paths {
81102
82393
  "application/json": components["schemas"]["OutboundVerdictError"];
81103
82394
  };
81104
82395
  };
81105
- /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact, an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
82396
+ /** @description `OUTBOUND_BLOCKED` — a Bloqueo de envío: an opted-out contact (a single free-text reply to a customer who wrote in again after THEIR OWN opt-out passes inside the WhatsApp / Instagram / Messenger 24-hour window, or in the same email thread; a block your team set or a spam complaint still refuses), an active hold, a closed WhatsApp 24-hour window with no template, a template Meta will reject, no channel identity, a disconnected or red account. Never overridable; `error.hint` says what to do instead. */
81106
82397
  422: {
81107
82398
  headers: {
81108
82399
  [name: string]: unknown;
@@ -92001,7 +93292,7 @@ interface paths {
92001
93292
  patch?: never;
92002
93293
  trace?: never;
92003
93294
  };
92004
- "/insights/overview/live": {
93295
+ "/insights/resultados": {
92005
93296
  parameters: {
92006
93297
  query?: never;
92007
93298
  header?: never;
@@ -92009,19 +93300,26 @@ interface paths {
92009
93300
  cookie?: never;
92010
93301
  };
92011
93302
  /**
92012
- * Current live activity
92013
- * @description A now-snapshot: open conversations, who is waiting, what is in flight. The one report that takes NO range — it describes the present, so `from`/`to` would mean nothing and are not accepted.
93303
+ * What the AI did for the agenda (any vertical)
93304
+ * @description The same facts as `GET /clinic/insights/resultados`, for any vertical, with the vertical's vocabulary (`family`: a dealer reads visits and test drives, `clientes`). Blocks with no data for the vertical come back `applies: false` (money, confirmation, reminders for a dealer) rather than as zeros. Aggregates only. Requires `analytics:read`; CLP figures additionally require `clinic_money:read`. Accepts `from` / `to` (bare `YYYY-MM-DD`, `to` inclusive; default the 90 days ending today) and `location_id`.
92014
93305
  */
92015
93306
  get: {
92016
93307
  parameters: {
92017
- query?: never;
93308
+ query?: {
93309
+ /** @description First day of the window (by the day the cita happens), inclusive. Defaults to 90 days before `to`. */
93310
+ from?: string;
93311
+ /** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
93312
+ to?: string;
93313
+ /** @description One sucursal. Omit for all of them. */
93314
+ location_id?: string;
93315
+ };
92018
93316
  header?: never;
92019
93317
  path?: never;
92020
93318
  cookie?: never;
92021
93319
  };
92022
93320
  requestBody?: never;
92023
93321
  responses: {
92024
- /** @description Live activity snapshot */
93322
+ /** @description Tu día con Vitrina */
92025
93323
  200: {
92026
93324
  headers: {
92027
93325
  [name: string]: unknown;
@@ -92030,28 +93328,158 @@ interface paths {
92030
93328
  /**
92031
93329
  * @example {
92032
93330
  * "data": {
92033
- * "open": 14,
92034
- * "unattended": 0,
92035
- * "unassigned": 1,
92036
- * "pending": 0,
92037
- * "agents_online": 1,
92038
- * "agents_busy": 0,
92039
- * "agents_offline": 4
92040
- * },
92041
- * "meta": {
92042
- * "window": {
92043
- * "kind": "instant",
92044
- * "at": "2026-09-22T16:38:43.071Z",
92045
- * "label": "ahora"
92046
- * }
93331
+ * "from": "2026-07-01",
93332
+ * "to": "2026-09-28",
93333
+ * "timezone": "America/Santiago",
93334
+ * "location_id": null,
93335
+ * "family": "clinic",
93336
+ * "previous_period": {
93337
+ * "from": "2026-04-02",
93338
+ * "to": "2026-06-30"
93339
+ * },
93340
+ * "bookings": {
93341
+ * "ai": 286,
93342
+ * "agenda_total": 2011,
93343
+ * "share_pct": 14.2,
93344
+ * "previous": {
93345
+ * "ai": 240,
93346
+ * "agenda_total": 1950,
93347
+ * "share_pct": 12.3
93348
+ * },
93349
+ * "rule": "Citas del período (por la fecha de la cita) que agendó el asistente de Vitrina en una conversación, ÷ todas las citas del período."
93350
+ * },
93351
+ * "money": {
93352
+ * "applies": true,
93353
+ * "withheld": false,
93354
+ * "booked_clp": 11400000,
93355
+ * "booked_priced": 271,
93356
+ * "booked_unpriced": 15,
93357
+ * "agenda_clp": 96000000,
93358
+ * "clp_share_pct": 11.9,
93359
+ * "paid_clp": 7250000,
93360
+ * "paid_patients": 164,
93361
+ * "unlinked": 4,
93362
+ * "regime": "mirror",
93363
+ * "previous": {
93364
+ * "booked_clp": 9800000,
93365
+ * "paid_clp": 6100000
93366
+ * },
93367
+ * "rule_booked": "Valor de las citas que agendó Vitrina: el precio de sus prestaciones, o el del catálogo. Es lo agendado, no lo cobrado.",
93368
+ * "rule_paid": "Pagos recibidos en el período por los pacientes que Vitrina agendó, desde el día en que los agendó."
93369
+ * },
93370
+ * "out_of_hours": {
93371
+ * "configured": true,
93372
+ * "count": 111,
93373
+ * "pct": 38.8,
93374
+ * "previous_pct": 36.1,
93375
+ * "heatmap": [
93376
+ * {
93377
+ * "weekday": 1,
93378
+ * "hour": 21,
93379
+ * "count": 9
93380
+ * },
93381
+ * {
93382
+ * "weekday": 6,
93383
+ * "hour": 11,
93384
+ * "count": 14
93385
+ * }
93386
+ * ],
93387
+ * "rule": "Citas que Vitrina agendó mientras tu negocio estaba cerrado, según tu horario de atención (incluye feriados)."
93388
+ * },
93389
+ * "autonomy": {
93390
+ * "no_human": 158,
93391
+ * "pct": 56.6,
93392
+ * "measured": 279,
93393
+ * "unknown": 7,
93394
+ * "previous_pct": 52,
93395
+ * "rule": "Citas de Vitrina en las que nadie de tu equipo escribió en la conversación antes de agendar."
93396
+ * },
93397
+ * "time_to_book": {
93398
+ * "median_seconds": 734,
93399
+ * "p95_seconds": 80100,
93400
+ * "p95_phrase": "5 de cada 100 personas tardan más de 22 h 15 min en quedar agendadas.",
93401
+ * "measured": 279,
93402
+ * "unknown": 7,
93403
+ * "previous_median_seconds": 910,
93404
+ * "rule": "Tiempo desde el primer mensaje del paciente hasta que su cita quedó agendada (la mediana)."
93405
+ * },
93406
+ * "hours_returned": {
93407
+ * "minutes_per_booking": 10,
93408
+ * "hours": 47.7,
93409
+ * "rule": "Cada cita que agenda Vitrina ahorra 10 minutos de responder y agendar a mano."
93410
+ * },
93411
+ * "recovery": {
93412
+ * "window_days": 30,
93413
+ * "known_attendance": 1063,
93414
+ * "unknown_attendance": 21,
93415
+ * "no_show_pct": 10.2,
93416
+ * "no_show": {
93417
+ * "count": 108,
93418
+ * "recovered": 37,
93419
+ * "recovered_via_vitrina": 17,
93420
+ * "recovered_pct": 34.6,
93421
+ * "via_vitrina_pct": 15.9,
93422
+ * "pending": 12,
93423
+ * "unlinked": 1
93424
+ * },
93425
+ * "cancelled": {
93426
+ * "count": 240,
93427
+ * "recovered": 26,
93428
+ * "recovered_via_vitrina": 11,
93429
+ * "recovered_pct": 10.8,
93430
+ * "via_vitrina_pct": 4.6,
93431
+ * "pending": 18,
93432
+ * "unlinked": 0
93433
+ * },
93434
+ * "rule_no_show": "Citas pasadas marcadas como «no asistió» ÷ citas con asistencia conocida (asistió + no asistió).",
93435
+ * "rule_recovered": "Una cita perdida se recupera cuando el mismo paciente agenda otra dentro de 30 días."
93436
+ * },
93437
+ * "confirmation": {
93438
+ * "applies": true,
93439
+ * "confirmed_attendance_pct": 93.1,
93440
+ * "unconfirmed_attendance_pct": 78.4,
93441
+ * "confirmed_closed": 610,
93442
+ * "unconfirmed_closed": 212,
93443
+ * "rule": "Asistencia de las citas cuyo paciente confirmó el recordatorio, frente a las que nunca respondieron."
93444
+ * },
93445
+ * "ads": {
93446
+ * "state": "active",
93447
+ * "spend_clp": 1648000,
93448
+ * "booked": 58,
93449
+ * "attended": 41,
93450
+ * "paid": 22,
93451
+ * "cost_per_booked": 28414,
93452
+ * "cost_per_attended": 40195,
93453
+ * "cost_per_paid": 74909,
93454
+ * "rule": "Inversión en anuncios del período ÷ citas agendadas, asistidas y pacientes que pagaron por primera vez, según Vitrina Ads para las mismas fechas."
93455
+ * },
93456
+ * "reminders": {
93457
+ * "applies": true,
93458
+ * "sent": 721,
93459
+ * "failed": 120,
93460
+ * "failed_pct": 14.3,
93461
+ * "by_cause": [
93462
+ * {
93463
+ * "cause": "no_whatsapp",
93464
+ * "count": 61
93465
+ * },
93466
+ * {
93467
+ * "cause": "no_phone",
93468
+ * "count": 38
93469
+ * },
93470
+ * {
93471
+ * "cause": "meta_payment_block",
93472
+ * "count": 21
93473
+ * }
93474
+ * ],
93475
+ * "rule": "Recordatorios de citas del período que no salieron, agrupados por la causa que registró el envío."
93476
+ * },
93477
+ * "truncated": false
92047
93478
  * }
92048
93479
  * }
92049
93480
  */
92050
93481
  "application/json": {
92051
- data?: unknown;
92052
- meta?: {
92053
- [key: string]: unknown;
92054
- };
93482
+ data: components["schemas"]["AgendaResults"];
92055
93483
  };
92056
93484
  };
92057
93485
  };
@@ -92119,7 +93547,7 @@ interface paths {
92119
93547
  patch?: never;
92120
93548
  trace?: never;
92121
93549
  };
92122
- "/insights/overview/heatmap": {
93550
+ "/insights/overview/live": {
92123
93551
  parameters: {
92124
93552
  query?: never;
92125
93553
  header?: never;
@@ -92127,32 +93555,19 @@ interface paths {
92127
93555
  cookie?: never;
92128
93556
  };
92129
93557
  /**
92130
- * Activity heatmap by day and hour
92131
- * @description The only report that accepts `tz`. Pass the viewer’s IANA zone (`America/Santiago`) and the day/hour buckets follow their wall clock; omit it and the grid is UTC, which shifts a Chilean workspace’s busy hours by three or four columns depending on DST. The name is validated by Postgres, so an unknown zone is a 500 rather than a 400.
93558
+ * Current live activity
93559
+ * @description A now-snapshot: open conversations, who is waiting, what is in flight. The one report that takes NO range — it describes the present, so `from`/`to` would mean nothing and are not accepted.
92132
93560
  */
92133
93561
  get: {
92134
93562
  parameters: {
92135
- query?: {
92136
- /** @description Which period. Omit it (with `from`/`to`) for an explicit range — the shape every ranged Insights report has always accepted, and which still works unchanged. The calendar windows are the DEALERSHIP’s (America/Santiago), so a month closes when a person would say it closed. */
92137
- window?: "24h" | "7d" | "30d" | "90d" | "calendar_month" | "calendar_year" | "custom";
92138
- /** @description `window=calendar_month` only. ISO month, `YYYY-MM`. Defaults to the month in progress. */
92139
- month?: string;
92140
- /** @description `window=calendar_year` only. `YYYY`. Defaults to the year in progress. */
92141
- year?: string;
92142
- /** @description Explicit range only. Checked for non-emptiness and handed to Postgres, so a malformed value surfaces as a 500 from the query rather than a 400 from the edge — send an ISO-8601 instant. */
92143
- from?: string;
92144
- /** @description Explicit range only. ISO instant, see `from`. */
92145
- to?: string;
92146
- /** @description IANA timezone for the date/hour buckets. Defaults to UTC. */
92147
- tz?: string;
92148
- };
93563
+ query?: never;
92149
93564
  header?: never;
92150
93565
  path?: never;
92151
93566
  cookie?: never;
92152
93567
  };
92153
93568
  requestBody?: never;
92154
93569
  responses: {
92155
- /** @description Day/hour activity buckets */
93570
+ /** @description Live activity snapshot */
92156
93571
  200: {
92157
93572
  headers: {
92158
93573
  [name: string]: unknown;
@@ -92161,27 +93576,19 @@ interface paths {
92161
93576
  /**
92162
93577
  * @example {
92163
93578
  * "data": {
92164
- * "buckets": [
92165
- * {
92166
- * "day": 1,
92167
- * "hour": 10,
92168
- * "conversations": 3
92169
- * },
92170
- * {
92171
- * "day": 1,
92172
- * "hour": 11,
92173
- * "conversations": 5
92174
- * }
92175
- * ]
93579
+ * "open": 14,
93580
+ * "unattended": 0,
93581
+ * "unassigned": 1,
93582
+ * "pending": 0,
93583
+ * "agents_online": 1,
93584
+ * "agents_busy": 0,
93585
+ * "agents_offline": 4
92176
93586
  * },
92177
93587
  * "meta": {
92178
93588
  * "window": {
92179
- * "kind": "rolling",
92180
- * "preset": "7d",
92181
- * "hours": 168,
92182
- * "from": "2026-09-15T16:38:51.000Z",
92183
- * "to": "2026-09-22T16:38:51.000Z",
92184
- * "label": "últimos 7d"
93589
+ * "kind": "instant",
93590
+ * "at": "2026-09-22T16:38:43.071Z",
93591
+ * "label": "ahora"
92185
93592
  * }
92186
93593
  * }
92187
93594
  * }
@@ -92258,7 +93665,7 @@ interface paths {
92258
93665
  patch?: never;
92259
93666
  trace?: never;
92260
93667
  };
92261
- "/insights/calls": {
93668
+ "/insights/overview/heatmap": {
92262
93669
  parameters: {
92263
93670
  query?: never;
92264
93671
  header?: never;
@@ -92266,8 +93673,8 @@ interface paths {
92266
93673
  cookie?: never;
92267
93674
  };
92268
93675
  /**
92269
- * Voice call statistics
92270
- * @description Voice-channel call stats for the window. Served by the voice insights service rather than the general reporting one, so its shape does not match the other reports.
93676
+ * Activity heatmap by day and hour
93677
+ * @description The only report that accepts `tz`. Pass the viewer’s IANA zone (`America/Santiago`) and the day/hour buckets follow their wall clock; omit it and the grid is UTC, which shifts a Chilean workspace’s busy hours by three or four columns depending on DST. The name is validated by Postgres, so an unknown zone is a 500 rather than a 400.
92271
93678
  */
92272
93679
  get: {
92273
93680
  parameters: {
@@ -92282,6 +93689,8 @@ interface paths {
92282
93689
  from?: string;
92283
93690
  /** @description Explicit range only. ISO instant, see `from`. */
92284
93691
  to?: string;
93692
+ /** @description IANA timezone for the date/hour buckets. Defaults to UTC. */
93693
+ tz?: string;
92285
93694
  };
92286
93695
  header?: never;
92287
93696
  path?: never;
@@ -92289,7 +93698,7 @@ interface paths {
92289
93698
  };
92290
93699
  requestBody?: never;
92291
93700
  responses: {
92292
- /** @description Call statistics */
93701
+ /** @description Day/hour activity buckets */
92293
93702
  200: {
92294
93703
  headers: {
92295
93704
  [name: string]: unknown;
@@ -92298,30 +93707,167 @@ interface paths {
92298
93707
  /**
92299
93708
  * @example {
92300
93709
  * "data": {
92301
- * "range": {
92302
- * "from": "2026-09-15T16:38:51.540Z",
92303
- * "to": "2026-09-22T16:38:51.540Z"
92304
- * },
92305
- * "calls": {
92306
- * "total": 6,
92307
- * "answered": 5,
92308
- * "avg_duration_s": 142,
92309
- * "by_outcome": {
92310
- * "completed": 5,
92311
- * "no_answer": 1
92312
- * },
92313
- * "by_direction": {
92314
- * "inbound": 4,
92315
- * "outbound": 2
93710
+ * "buckets": [
93711
+ * {
93712
+ * "day": 1,
93713
+ * "hour": 10,
93714
+ * "conversations": 3
92316
93715
  * },
92317
- * "by_amd": {}
92318
- * },
92319
- * "latency": {
92320
- * "voice_to_voice": 820,
92321
- * "voice_llm_turn": 410,
92322
- * "voice_llm_first_token": 190,
92323
- * "tool_execution": 260
92324
- * }
93716
+ * {
93717
+ * "day": 1,
93718
+ * "hour": 11,
93719
+ * "conversations": 5
93720
+ * }
93721
+ * ]
93722
+ * },
93723
+ * "meta": {
93724
+ * "window": {
93725
+ * "kind": "rolling",
93726
+ * "preset": "7d",
93727
+ * "hours": 168,
93728
+ * "from": "2026-09-15T16:38:51.000Z",
93729
+ * "to": "2026-09-22T16:38:51.000Z",
93730
+ * "label": "últimos 7d"
93731
+ * }
93732
+ * }
93733
+ * }
93734
+ */
93735
+ "application/json": {
93736
+ data?: unknown;
93737
+ meta?: {
93738
+ [key: string]: unknown;
93739
+ };
93740
+ };
93741
+ };
93742
+ };
93743
+ /** @description Validation error */
93744
+ 400: {
93745
+ headers: {
93746
+ [name: string]: unknown;
93747
+ };
93748
+ content: {
93749
+ "application/json": components["schemas"]["Error"];
93750
+ };
93751
+ };
93752
+ /** @description Unauthorized */
93753
+ 401: {
93754
+ headers: {
93755
+ [name: string]: unknown;
93756
+ };
93757
+ content: {
93758
+ "application/json": components["schemas"]["Error"];
93759
+ };
93760
+ };
93761
+ /** @description Forbidden */
93762
+ 403: {
93763
+ headers: {
93764
+ [name: string]: unknown;
93765
+ };
93766
+ content: {
93767
+ "application/json": components["schemas"]["Error"];
93768
+ };
93769
+ };
93770
+ /** @description Not found */
93771
+ 404: {
93772
+ headers: {
93773
+ [name: string]: unknown;
93774
+ };
93775
+ content: {
93776
+ "application/json": components["schemas"]["Error"];
93777
+ };
93778
+ };
93779
+ /** @description Conflict (incl. Idempotency-Key reuse with different body) */
93780
+ 409: {
93781
+ headers: {
93782
+ [name: string]: unknown;
93783
+ };
93784
+ content: {
93785
+ "application/json": components["schemas"]["Error"];
93786
+ };
93787
+ };
93788
+ /** @description Rate limited */
93789
+ 429: {
93790
+ headers: {
93791
+ [name: string]: unknown;
93792
+ };
93793
+ content: {
93794
+ "application/json": components["schemas"]["Error"];
93795
+ };
93796
+ };
93797
+ };
93798
+ };
93799
+ put?: never;
93800
+ post?: never;
93801
+ delete?: never;
93802
+ options?: never;
93803
+ head?: never;
93804
+ patch?: never;
93805
+ trace?: never;
93806
+ };
93807
+ "/insights/calls": {
93808
+ parameters: {
93809
+ query?: never;
93810
+ header?: never;
93811
+ path?: never;
93812
+ cookie?: never;
93813
+ };
93814
+ /**
93815
+ * Voice call statistics
93816
+ * @description Voice-channel call stats for the window. Served by the voice insights service rather than the general reporting one, so its shape does not match the other reports.
93817
+ */
93818
+ get: {
93819
+ parameters: {
93820
+ query?: {
93821
+ /** @description Which period. Omit it (with `from`/`to`) for an explicit range — the shape every ranged Insights report has always accepted, and which still works unchanged. The calendar windows are the DEALERSHIP’s (America/Santiago), so a month closes when a person would say it closed. */
93822
+ window?: "24h" | "7d" | "30d" | "90d" | "calendar_month" | "calendar_year" | "custom";
93823
+ /** @description `window=calendar_month` only. ISO month, `YYYY-MM`. Defaults to the month in progress. */
93824
+ month?: string;
93825
+ /** @description `window=calendar_year` only. `YYYY`. Defaults to the year in progress. */
93826
+ year?: string;
93827
+ /** @description Explicit range only. Checked for non-emptiness and handed to Postgres, so a malformed value surfaces as a 500 from the query rather than a 400 from the edge — send an ISO-8601 instant. */
93828
+ from?: string;
93829
+ /** @description Explicit range only. ISO instant, see `from`. */
93830
+ to?: string;
93831
+ };
93832
+ header?: never;
93833
+ path?: never;
93834
+ cookie?: never;
93835
+ };
93836
+ requestBody?: never;
93837
+ responses: {
93838
+ /** @description Call statistics */
93839
+ 200: {
93840
+ headers: {
93841
+ [name: string]: unknown;
93842
+ };
93843
+ content: {
93844
+ /**
93845
+ * @example {
93846
+ * "data": {
93847
+ * "range": {
93848
+ * "from": "2026-09-15T16:38:51.540Z",
93849
+ * "to": "2026-09-22T16:38:51.540Z"
93850
+ * },
93851
+ * "calls": {
93852
+ * "total": 6,
93853
+ * "answered": 5,
93854
+ * "avg_duration_s": 142,
93855
+ * "by_outcome": {
93856
+ * "completed": 5,
93857
+ * "no_answer": 1
93858
+ * },
93859
+ * "by_direction": {
93860
+ * "inbound": 4,
93861
+ * "outbound": 2
93862
+ * },
93863
+ * "by_amd": {}
93864
+ * },
93865
+ * "latency": {
93866
+ * "voice_to_voice": 820,
93867
+ * "voice_llm_turn": 410,
93868
+ * "voice_llm_first_token": 190,
93869
+ * "tool_execution": 260
93870
+ * }
92325
93871
  * },
92326
93872
  * "meta": {
92327
93873
  * "window": {
@@ -96503,6 +98049,593 @@ interface paths {
96503
98049
  patch?: never;
96504
98050
  trace?: never;
96505
98051
  };
98052
+ "/ads/report": {
98053
+ parameters: {
98054
+ query?: never;
98055
+ header?: never;
98056
+ path?: never;
98057
+ cookie?: never;
98058
+ };
98059
+ /**
98060
+ * Reporte: campaigns, ad sets or ads with their funnel, costs and cash return
98061
+ * @description One table at `level` (campaign, ad set or ad) for the window. Per row: the spend and the cash credited by the attribution engine, Vitrina’s own conversational funnel (conversations each ad opened → answered → citas → attended → closes) with the cost of each step, «Retorno» = cash ÷ spend (`null` when no payment was recorded in the period), and Meta’s own figures apart. `tail` holds the period’s conversations with no ad behind them, so from-ads + tail = the workspace total; `reconciliation` states Σ spend against `/ads/overview`. A failed read is `null`, never 0.
98062
+ */
98063
+ get: {
98064
+ parameters: {
98065
+ query: {
98066
+ /** @description Window start (inclusive), YYYY-MM-DD. */
98067
+ from: string;
98068
+ /** @description Window end (inclusive), YYYY-MM-DD. */
98069
+ to: string;
98070
+ /** @description The attribution model. Defaults to `last_touch`. */
98071
+ model?: string;
98072
+ /** @description `1` serves the deterministic sample dataset («Ver con datos de ejemplo»): same shapes, invented but internally consistent figures, no entitlement required (the scope still is). A sandbox workspace is always served the sample, with or without this parameter. */
98073
+ sample?: "1" | "true";
98074
+ /** @description Campaña, conjunto (ad set) or anuncio. Default `campaign`. */
98075
+ level?: "campaign" | "ad_set" | "ad";
98076
+ };
98077
+ header?: never;
98078
+ path?: never;
98079
+ cookie?: never;
98080
+ };
98081
+ requestBody?: never;
98082
+ responses: {
98083
+ /** @description The report at the requested level */
98084
+ 200: {
98085
+ headers: {
98086
+ [name: string]: unknown;
98087
+ };
98088
+ content: {
98089
+ /**
98090
+ * @example {
98091
+ * "data": {
98092
+ * "level": "campaign",
98093
+ * "window": {
98094
+ * "from": "2026-08-30",
98095
+ * "to": "2026-09-28"
98096
+ * },
98097
+ * "rows": [
98098
+ * {
98099
+ * "external_id": "120211000000000001",
98100
+ * "level": "campaign",
98101
+ * "name": "Implantes · Septiembre",
98102
+ * "parent": null,
98103
+ * "thumbnail_url": null,
98104
+ * "spark": [
98105
+ * 13200,
98106
+ * 14100,
98107
+ * 13900
98108
+ * ],
98109
+ * "spend": 412300,
98110
+ * "funnel": {
98111
+ * "conversations": 120,
98112
+ * "replied": 110,
98113
+ * "appointments": 20,
98114
+ * "attended": 12,
98115
+ * "closes": 2
98116
+ * },
98117
+ * "cost_per": {
98118
+ * "conversation": 3436,
98119
+ * "appointment": 20615,
98120
+ * "attended": 34358,
98121
+ * "close": 206150
98122
+ * },
98123
+ * "cash": 0,
98124
+ * "return": null,
98125
+ * "meta": {
98126
+ * "conversations_started": 131,
98127
+ * "cost_per_conversation": 3147
98128
+ * }
98129
+ * }
98130
+ * ],
98131
+ * "tail": [
98132
+ * {
98133
+ * "key": "direct",
98134
+ * "conversations": 210
98135
+ * },
98136
+ * {
98137
+ * "key": "website",
98138
+ * "conversations": 40
98139
+ * }
98140
+ * ],
98141
+ * "totals": {
98142
+ * "spend": 412300,
98143
+ * "funnel": {
98144
+ * "conversations": 120,
98145
+ * "replied": 110,
98146
+ * "appointments": 20,
98147
+ * "attended": 12,
98148
+ * "closes": 2
98149
+ * },
98150
+ * "cost_per": {
98151
+ * "conversation": 3436,
98152
+ * "appointment": 20615,
98153
+ * "attended": 34358,
98154
+ * "close": 206150
98155
+ * },
98156
+ * "cash": 0,
98157
+ * "return": null,
98158
+ * "meta": {
98159
+ * "conversations_started": 131,
98160
+ * "cost_per_conversation": 3147
98161
+ * }
98162
+ * },
98163
+ * "pipeline": {
98164
+ * "closed_count": 3,
98165
+ * "closed_value": 93082
98166
+ * },
98167
+ * "cash_recorded": false,
98168
+ * "reconciliation": {
98169
+ * "overview_spend": 412300,
98170
+ * "spend_matches": true,
98171
+ * "conversations_total": 370,
98172
+ * "conversations_from_ads": 120,
98173
+ * "conversations_without_ad": 250
98174
+ * }
98175
+ * }
98176
+ * }
98177
+ */
98178
+ "application/json": {
98179
+ data: components["schemas"]["AdsReport"];
98180
+ };
98181
+ };
98182
+ };
98183
+ /** @description Validation error */
98184
+ 400: {
98185
+ headers: {
98186
+ [name: string]: unknown;
98187
+ };
98188
+ content: {
98189
+ "application/json": components["schemas"]["Error"];
98190
+ };
98191
+ };
98192
+ /** @description Unauthorized */
98193
+ 401: {
98194
+ headers: {
98195
+ [name: string]: unknown;
98196
+ };
98197
+ content: {
98198
+ "application/json": components["schemas"]["Error"];
98199
+ };
98200
+ };
98201
+ /** @description Vitrina Ads is not active for this workspace. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. */
98202
+ 402: {
98203
+ headers: {
98204
+ [name: string]: unknown;
98205
+ };
98206
+ content: {
98207
+ /**
98208
+ * @example {
98209
+ * "error": {
98210
+ * "code": "ENTITLEMENT_NOT_ACTIVE",
98211
+ * "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
98212
+ * "details": {
98213
+ * "required": [
98214
+ * "vitrina_ads"
98215
+ * ],
98216
+ * "active": [],
98217
+ * "feature": "vitrina_ads",
98218
+ * "entitlement_state": "off"
98219
+ * }
98220
+ * }
98221
+ * }
98222
+ */
98223
+ "application/json": components["schemas"]["Error"];
98224
+ };
98225
+ };
98226
+ /** @description Forbidden */
98227
+ 403: {
98228
+ headers: {
98229
+ [name: string]: unknown;
98230
+ };
98231
+ content: {
98232
+ "application/json": components["schemas"]["Error"];
98233
+ };
98234
+ };
98235
+ /** @description Not found */
98236
+ 404: {
98237
+ headers: {
98238
+ [name: string]: unknown;
98239
+ };
98240
+ content: {
98241
+ "application/json": components["schemas"]["Error"];
98242
+ };
98243
+ };
98244
+ /** @description Vitrina Ads is active but the delegated key has not finished rotating (`ADS_KEY_NEEDS_REMINT`) — retry once `GET /ads/state` reports `needs_remint: false`. Also the generic conflict of a write. */
98245
+ 409: {
98246
+ headers: {
98247
+ [name: string]: unknown;
98248
+ };
98249
+ content: {
98250
+ /**
98251
+ * @example {
98252
+ * "error": {
98253
+ * "code": "ADS_KEY_NEEDS_REMINT",
98254
+ * "message": "Vitrina Ads is active but the delegated key has not finished rotating (key_kind: core)",
98255
+ * "details": {
98256
+ * "key_kind": "core"
98257
+ * }
98258
+ * }
98259
+ * }
98260
+ */
98261
+ "application/json": components["schemas"]["Error"];
98262
+ };
98263
+ };
98264
+ /** @description Rate limited */
98265
+ 429: {
98266
+ headers: {
98267
+ [name: string]: unknown;
98268
+ };
98269
+ content: {
98270
+ "application/json": components["schemas"]["Error"];
98271
+ };
98272
+ };
98273
+ };
98274
+ };
98275
+ put?: never;
98276
+ post?: never;
98277
+ delete?: never;
98278
+ options?: never;
98279
+ head?: never;
98280
+ patch?: never;
98281
+ trace?: never;
98282
+ };
98283
+ "/ads/report/export": {
98284
+ parameters: {
98285
+ query?: never;
98286
+ header?: never;
98287
+ path?: never;
98288
+ cookie?: never;
98289
+ };
98290
+ /**
98291
+ * Export the Reporte (aggregates only)
98292
+ * @description The same table as `GET /ads/report`, as a file. CSV: `;`, Spanish headers, `dd-mm-aaaa` dates, a preamble with the period, the model and «Retorno = caja». XLSX: the table plus a «Notas» sheet. No row names a person. Audited as `ads.report.export`.
98293
+ */
98294
+ get: {
98295
+ parameters: {
98296
+ query: {
98297
+ /** @description Window start (inclusive), YYYY-MM-DD. */
98298
+ from: string;
98299
+ /** @description Window end (inclusive), YYYY-MM-DD. */
98300
+ to: string;
98301
+ /** @description The attribution model. Defaults to `last_touch`. */
98302
+ model?: string;
98303
+ /** @description `1` serves the deterministic sample dataset («Ver con datos de ejemplo»): same shapes, invented but internally consistent figures, no entitlement required (the scope still is). A sandbox workspace is always served the sample, with or without this parameter. */
98304
+ sample?: "1" | "true";
98305
+ /** @description Campaña, conjunto (ad set) or anuncio. Default `campaign`. */
98306
+ level?: "campaign" | "ad_set" | "ad";
98307
+ /** @description `csv`: `;`-separated, Spanish headers, `dd-mm-aaaa` dates, a preamble with the period, the model and «Retorno = caja». `xlsx`: the same table plus a «Notas» sheet. Aggregates only — no person rows. */
98308
+ format?: "csv" | "xlsx";
98309
+ };
98310
+ header?: never;
98311
+ path?: never;
98312
+ cookie?: never;
98313
+ };
98314
+ requestBody?: never;
98315
+ responses: {
98316
+ /** @description The file */
98317
+ 200: {
98318
+ headers: {
98319
+ [name: string]: unknown;
98320
+ };
98321
+ content: {
98322
+ "text/csv": string;
98323
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": string;
98324
+ };
98325
+ };
98326
+ /** @description Validation error */
98327
+ 400: {
98328
+ headers: {
98329
+ [name: string]: unknown;
98330
+ };
98331
+ content: {
98332
+ "application/json": components["schemas"]["Error"];
98333
+ };
98334
+ };
98335
+ /** @description Unauthorized */
98336
+ 401: {
98337
+ headers: {
98338
+ [name: string]: unknown;
98339
+ };
98340
+ content: {
98341
+ "application/json": components["schemas"]["Error"];
98342
+ };
98343
+ };
98344
+ /** @description Vitrina Ads is not active for this workspace. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. */
98345
+ 402: {
98346
+ headers: {
98347
+ [name: string]: unknown;
98348
+ };
98349
+ content: {
98350
+ /**
98351
+ * @example {
98352
+ * "error": {
98353
+ * "code": "ENTITLEMENT_NOT_ACTIVE",
98354
+ * "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
98355
+ * "details": {
98356
+ * "required": [
98357
+ * "vitrina_ads"
98358
+ * ],
98359
+ * "active": [],
98360
+ * "feature": "vitrina_ads",
98361
+ * "entitlement_state": "off"
98362
+ * }
98363
+ * }
98364
+ * }
98365
+ */
98366
+ "application/json": components["schemas"]["Error"];
98367
+ };
98368
+ };
98369
+ /** @description Forbidden */
98370
+ 403: {
98371
+ headers: {
98372
+ [name: string]: unknown;
98373
+ };
98374
+ content: {
98375
+ "application/json": components["schemas"]["Error"];
98376
+ };
98377
+ };
98378
+ /** @description Not found */
98379
+ 404: {
98380
+ headers: {
98381
+ [name: string]: unknown;
98382
+ };
98383
+ content: {
98384
+ "application/json": components["schemas"]["Error"];
98385
+ };
98386
+ };
98387
+ /** @description Vitrina Ads is active but the delegated key has not finished rotating (`ADS_KEY_NEEDS_REMINT`) — retry once `GET /ads/state` reports `needs_remint: false`. Also the generic conflict of a write. */
98388
+ 409: {
98389
+ headers: {
98390
+ [name: string]: unknown;
98391
+ };
98392
+ content: {
98393
+ /**
98394
+ * @example {
98395
+ * "error": {
98396
+ * "code": "ADS_KEY_NEEDS_REMINT",
98397
+ * "message": "Vitrina Ads is active but the delegated key has not finished rotating (key_kind: core)",
98398
+ * "details": {
98399
+ * "key_kind": "core"
98400
+ * }
98401
+ * }
98402
+ * }
98403
+ */
98404
+ "application/json": components["schemas"]["Error"];
98405
+ };
98406
+ };
98407
+ /** @description Rate limited */
98408
+ 429: {
98409
+ headers: {
98410
+ [name: string]: unknown;
98411
+ };
98412
+ content: {
98413
+ "application/json": components["schemas"]["Error"];
98414
+ };
98415
+ };
98416
+ };
98417
+ };
98418
+ put?: never;
98419
+ post?: never;
98420
+ delete?: never;
98421
+ options?: never;
98422
+ head?: never;
98423
+ patch?: never;
98424
+ trace?: never;
98425
+ };
98426
+ "/ads/ads/{id}": {
98427
+ parameters: {
98428
+ query?: never;
98429
+ header?: never;
98430
+ path?: never;
98431
+ cookie?: never;
98432
+ };
98433
+ /**
98434
+ * The ad sheet: creative, funnel and the people it brought (masked)
98435
+ * @description One ad: the creative and delivery metrics, the SAME funnel/costs/cash as its Reporte row for the window, and the conversations it opened (a label, the furthest stage, its value). Never a phone or an e-mail; for healthcare the label is always initials. There is no export of people.
98436
+ */
98437
+ get: {
98438
+ parameters: {
98439
+ query: {
98440
+ /** @description Window start (inclusive), YYYY-MM-DD. */
98441
+ from: string;
98442
+ /** @description Window end (inclusive), YYYY-MM-DD. */
98443
+ to: string;
98444
+ /** @description The attribution model. Defaults to `last_touch`. */
98445
+ model?: string;
98446
+ /** @description `1` serves the deterministic sample dataset («Ver con datos de ejemplo»): same shapes, invented but internally consistent figures, no entitlement required (the scope still is). A sandbox workspace is always served the sample, with or without this parameter. */
98447
+ sample?: "1" | "true";
98448
+ };
98449
+ header?: never;
98450
+ path: {
98451
+ id: string;
98452
+ };
98453
+ cookie?: never;
98454
+ };
98455
+ requestBody?: never;
98456
+ responses: {
98457
+ /** @description The ad sheet */
98458
+ 200: {
98459
+ headers: {
98460
+ [name: string]: unknown;
98461
+ };
98462
+ content: {
98463
+ /**
98464
+ * @example {
98465
+ * "data": {
98466
+ * "ad": {
98467
+ * "external_id": "120212000000000009",
98468
+ * "name": "Video testimonio 15s",
98469
+ * "ad_set": {
98470
+ * "external_id": "120213000000000004",
98471
+ * "name": "INTERESES"
98472
+ * },
98473
+ * "campaign": {
98474
+ * "external_id": "120211000000000001"
98475
+ * },
98476
+ * "thumbnail_url": null,
98477
+ * "title": "Implantes en un día",
98478
+ * "body": "Agenda tu evaluación.",
98479
+ * "has_video": true,
98480
+ * "spend": 168000,
98481
+ * "impressions": 24100,
98482
+ * "clicks": 337,
98483
+ * "ctr": 1.4,
98484
+ * "cpm": 6971,
98485
+ * "cpc": 498,
98486
+ * "cash_count": 0,
98487
+ * "cash_value": 0,
98488
+ * "meta_conversations_started": 22
98489
+ * },
98490
+ * "window": {
98491
+ * "from": "2026-08-30",
98492
+ * "to": "2026-09-28"
98493
+ * },
98494
+ * "row": {
98495
+ * "spend": 412300,
98496
+ * "funnel": {
98497
+ * "conversations": 120,
98498
+ * "replied": 110,
98499
+ * "appointments": 20,
98500
+ * "attended": 12,
98501
+ * "closes": 2
98502
+ * },
98503
+ * "cost_per": {
98504
+ * "conversation": 3436,
98505
+ * "appointment": 20615,
98506
+ * "attended": 34358,
98507
+ * "close": 206150
98508
+ * },
98509
+ * "cash": 0,
98510
+ * "return": null,
98511
+ * "meta": {
98512
+ * "conversations_started": 131,
98513
+ * "cost_per_conversation": 3147
98514
+ * }
98515
+ * },
98516
+ * "cash_recorded": false,
98517
+ * "people": [
98518
+ * {
98519
+ * "conversation_id": "00000000-0000-4000-8000-00000000c0a1",
98520
+ * "contact_id": "00000000-0000-4000-8000-00000000c0a2",
98521
+ * "label": "M. R.",
98522
+ * "masked": true,
98523
+ * "stage": "closed_won",
98524
+ * "stage_at": "2026-09-25T15:00:00.000Z",
98525
+ * "opened_at": "2026-09-20T13:10:00.000Z",
98526
+ * "value": 1250000
98527
+ * }
98528
+ * ],
98529
+ * "people_more": false,
98530
+ * "people_hidden": false
98531
+ * }
98532
+ * }
98533
+ */
98534
+ "application/json": {
98535
+ data: components["schemas"]["AdsAdSheet"];
98536
+ };
98537
+ };
98538
+ };
98539
+ /** @description Validation error */
98540
+ 400: {
98541
+ headers: {
98542
+ [name: string]: unknown;
98543
+ };
98544
+ content: {
98545
+ "application/json": components["schemas"]["Error"];
98546
+ };
98547
+ };
98548
+ /** @description Unauthorized */
98549
+ 401: {
98550
+ headers: {
98551
+ [name: string]: unknown;
98552
+ };
98553
+ content: {
98554
+ "application/json": components["schemas"]["Error"];
98555
+ };
98556
+ };
98557
+ /** @description Vitrina Ads is not active for this workspace. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. */
98558
+ 402: {
98559
+ headers: {
98560
+ [name: string]: unknown;
98561
+ };
98562
+ content: {
98563
+ /**
98564
+ * @example {
98565
+ * "error": {
98566
+ * "code": "ENTITLEMENT_NOT_ACTIVE",
98567
+ * "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
98568
+ * "details": {
98569
+ * "required": [
98570
+ * "vitrina_ads"
98571
+ * ],
98572
+ * "active": [],
98573
+ * "feature": "vitrina_ads",
98574
+ * "entitlement_state": "off"
98575
+ * }
98576
+ * }
98577
+ * }
98578
+ */
98579
+ "application/json": components["schemas"]["Error"];
98580
+ };
98581
+ };
98582
+ /** @description Forbidden */
98583
+ 403: {
98584
+ headers: {
98585
+ [name: string]: unknown;
98586
+ };
98587
+ content: {
98588
+ "application/json": components["schemas"]["Error"];
98589
+ };
98590
+ };
98591
+ /** @description Not found */
98592
+ 404: {
98593
+ headers: {
98594
+ [name: string]: unknown;
98595
+ };
98596
+ content: {
98597
+ "application/json": components["schemas"]["Error"];
98598
+ };
98599
+ };
98600
+ /** @description Vitrina Ads is active but the delegated key has not finished rotating (`ADS_KEY_NEEDS_REMINT`) — retry once `GET /ads/state` reports `needs_remint: false`. Also the generic conflict of a write. */
98601
+ 409: {
98602
+ headers: {
98603
+ [name: string]: unknown;
98604
+ };
98605
+ content: {
98606
+ /**
98607
+ * @example {
98608
+ * "error": {
98609
+ * "code": "ADS_KEY_NEEDS_REMINT",
98610
+ * "message": "Vitrina Ads is active but the delegated key has not finished rotating (key_kind: core)",
98611
+ * "details": {
98612
+ * "key_kind": "core"
98613
+ * }
98614
+ * }
98615
+ * }
98616
+ */
98617
+ "application/json": components["schemas"]["Error"];
98618
+ };
98619
+ };
98620
+ /** @description Rate limited */
98621
+ 429: {
98622
+ headers: {
98623
+ [name: string]: unknown;
98624
+ };
98625
+ content: {
98626
+ "application/json": components["schemas"]["Error"];
98627
+ };
98628
+ };
98629
+ };
98630
+ };
98631
+ put?: never;
98632
+ post?: never;
98633
+ delete?: never;
98634
+ options?: never;
98635
+ head?: never;
98636
+ patch?: never;
98637
+ trace?: never;
98638
+ };
96506
98639
  "/ads/overview": {
96507
98640
  parameters: {
96508
98641
  query?: never;
@@ -97088,6 +99221,17 @@ interface paths {
97088
99221
  * "attributed_outcomes": 1,
97089
99222
  * "partial": false
97090
99223
  * }
99224
+ * ],
99225
+ * "gaps": [
99226
+ * {
99227
+ * "from": "2026-09-12",
99228
+ * "to": "2026-09-15",
99229
+ * "cause": "meta_disconnected",
99230
+ * "metrics": [
99231
+ * "spend"
99232
+ * ],
99233
+ * "incident_id": "b1b1b1b1-0000-4000-8000-000000000002"
99234
+ * }
97091
99235
  * ]
97092
99236
  * }
97093
99237
  * }
@@ -97197,6 +99341,186 @@ interface paths {
97197
99341
  patch?: never;
97198
99342
  trace?: never;
97199
99343
  };
99344
+ "/ads/measurement": {
99345
+ parameters: {
99346
+ query?: never;
99347
+ header?: never;
99348
+ path?: never;
99349
+ cookie?: never;
99350
+ };
99351
+ /**
99352
+ * Measurement incidents: what stopped measuring, since when
99353
+ * @description The measurement watchdog’s ledger (W1.1, «Vigilancia de la medición»). `open` are the legs broken right now — the Meta ad account read (disconnected or stale), the site tag’s heartbeat, the Conversions API sends, a WhatsApp channel, clinic facts not reaching the attribution — each with the day the data stopped and its ONE fix (`action.path`). `recent` are the ones resolved in the last 14 days, with who fixed them.
99354
+ *
99355
+ * The owner and admins are told by WhatsApp and email at +0 h, +3 d and +7 d while an incident stays open. `/ads/overview` and `/ads/campaigns` carry the same incidents as `gaps` over their window.
99356
+ */
99357
+ get: {
99358
+ parameters: {
99359
+ query?: {
99360
+ /** @description `1` serves the deterministic sample dataset («Ver con datos de ejemplo»): same shapes, invented but internally consistent figures, no entitlement required (the scope still is). A sandbox workspace is always served the sample, with or without this parameter. */
99361
+ sample?: "1" | "true";
99362
+ };
99363
+ header?: never;
99364
+ path?: never;
99365
+ cookie?: never;
99366
+ };
99367
+ requestBody?: never;
99368
+ responses: {
99369
+ /** @description Open and recently resolved incidents */
99370
+ 200: {
99371
+ headers: {
99372
+ [name: string]: unknown;
99373
+ };
99374
+ content: {
99375
+ /**
99376
+ * @example {
99377
+ * "data": {
99378
+ * "open": [
99379
+ * {
99380
+ * "id": "b1b1b1b1-0000-4000-8000-000000000001",
99381
+ * "cause": "tag_silent",
99382
+ * "label": "Etiqueta del sitio sin señal",
99383
+ * "sentence": "La etiqueta de tu sitio web no envía visitas desde el 20 sep",
99384
+ * "action": {
99385
+ * "label": "Revisar la etiqueta",
99386
+ * "path": "/anuncios/activar?paso=tag"
99387
+ * },
99388
+ * "since": "2026-09-20T14:05:00.000Z",
99389
+ * "opened_at": "2026-09-27T15:00:00.000Z",
99390
+ * "resolved_at": null,
99391
+ * "resolution": null,
99392
+ * "resolved_by_name": null,
99393
+ * "metrics": []
99394
+ * }
99395
+ * ],
99396
+ * "recent": [
99397
+ * {
99398
+ * "id": "b1b1b1b1-0000-4000-8000-000000000002",
99399
+ * "cause": "meta_disconnected",
99400
+ * "label": "Meta Ads desconectado",
99401
+ * "sentence": "Tus anuncios de Meta dejaron de medirse el 12 sep",
99402
+ * "action": {
99403
+ * "label": "Reconectar Meta",
99404
+ * "path": "/anuncios/activar?paso=meta"
99405
+ * },
99406
+ * "since": "2026-09-12T11:20:00.000Z",
99407
+ * "opened_at": "2026-09-12T12:00:00.000Z",
99408
+ * "resolved_at": "2026-09-15T13:42:00.000Z",
99409
+ * "resolution": "reconnected",
99410
+ * "resolved_by_name": "Camila",
99411
+ * "metrics": [
99412
+ * "spend"
99413
+ * ]
99414
+ * }
99415
+ * ]
99416
+ * }
99417
+ * }
99418
+ */
99419
+ "application/json": {
99420
+ data: components["schemas"]["AdsMeasurement"];
99421
+ };
99422
+ };
99423
+ };
99424
+ /** @description Validation error */
99425
+ 400: {
99426
+ headers: {
99427
+ [name: string]: unknown;
99428
+ };
99429
+ content: {
99430
+ "application/json": components["schemas"]["Error"];
99431
+ };
99432
+ };
99433
+ /** @description Unauthorized */
99434
+ 401: {
99435
+ headers: {
99436
+ [name: string]: unknown;
99437
+ };
99438
+ content: {
99439
+ "application/json": components["schemas"]["Error"];
99440
+ };
99441
+ };
99442
+ /** @description Vitrina Ads is not active for this workspace. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. */
99443
+ 402: {
99444
+ headers: {
99445
+ [name: string]: unknown;
99446
+ };
99447
+ content: {
99448
+ /**
99449
+ * @example {
99450
+ * "error": {
99451
+ * "code": "ENTITLEMENT_NOT_ACTIVE",
99452
+ * "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
99453
+ * "details": {
99454
+ * "required": [
99455
+ * "vitrina_ads"
99456
+ * ],
99457
+ * "active": [],
99458
+ * "feature": "vitrina_ads",
99459
+ * "entitlement_state": "off"
99460
+ * }
99461
+ * }
99462
+ * }
99463
+ */
99464
+ "application/json": components["schemas"]["Error"];
99465
+ };
99466
+ };
99467
+ /** @description Forbidden */
99468
+ 403: {
99469
+ headers: {
99470
+ [name: string]: unknown;
99471
+ };
99472
+ content: {
99473
+ "application/json": components["schemas"]["Error"];
99474
+ };
99475
+ };
99476
+ /** @description Not found */
99477
+ 404: {
99478
+ headers: {
99479
+ [name: string]: unknown;
99480
+ };
99481
+ content: {
99482
+ "application/json": components["schemas"]["Error"];
99483
+ };
99484
+ };
99485
+ /** @description Vitrina Ads is active but the delegated key has not finished rotating (`ADS_KEY_NEEDS_REMINT`) — retry once `GET /ads/state` reports `needs_remint: false`. Also the generic conflict of a write. */
99486
+ 409: {
99487
+ headers: {
99488
+ [name: string]: unknown;
99489
+ };
99490
+ content: {
99491
+ /**
99492
+ * @example {
99493
+ * "error": {
99494
+ * "code": "ADS_KEY_NEEDS_REMINT",
99495
+ * "message": "Vitrina Ads is active but the delegated key has not finished rotating (key_kind: core)",
99496
+ * "details": {
99497
+ * "key_kind": "core"
99498
+ * }
99499
+ * }
99500
+ * }
99501
+ */
99502
+ "application/json": components["schemas"]["Error"];
99503
+ };
99504
+ };
99505
+ /** @description Rate limited */
99506
+ 429: {
99507
+ headers: {
99508
+ [name: string]: unknown;
99509
+ };
99510
+ content: {
99511
+ "application/json": components["schemas"]["Error"];
99512
+ };
99513
+ };
99514
+ };
99515
+ };
99516
+ put?: never;
99517
+ post?: never;
99518
+ delete?: never;
99519
+ options?: never;
99520
+ head?: never;
99521
+ patch?: never;
99522
+ trace?: never;
99523
+ };
97200
99524
  "/ads/campaigns": {
97201
99525
  parameters: {
97202
99526
  query?: never;
@@ -97412,6 +99736,17 @@ interface paths {
97412
99736
  * }
97413
99737
  * ]
97414
99738
  * }
99739
+ * ],
99740
+ * "gaps": [
99741
+ * {
99742
+ * "from": "2026-09-12",
99743
+ * "to": "2026-09-15",
99744
+ * "cause": "meta_disconnected",
99745
+ * "metrics": [
99746
+ * "spend"
99747
+ * ],
99748
+ * "incident_id": "b1b1b1b1-0000-4000-8000-000000000002"
99749
+ * }
97415
99750
  * ]
97416
99751
  * }
97417
99752
  * }
@@ -98036,6 +100371,29 @@ interface paths {
98036
100371
  * "outcomes": 42,
98037
100372
  * "attributed_outcomes": 31,
98038
100373
  * "coverage_percent": 73.8
100374
+ * },
100375
+ * "signals": {
100376
+ * "score": 72,
100377
+ * "components": [
100378
+ * {
100379
+ * "key": "meta",
100380
+ * "status": "ok",
100381
+ * "earned": 30,
100382
+ * "max": 30
100383
+ * },
100384
+ * {
100385
+ * "key": "origin",
100386
+ * "status": "partial",
100387
+ * "earned": 29.5,
100388
+ * "max": 40
100389
+ * },
100390
+ * {
100391
+ * "key": "site_tag",
100392
+ * "status": "partial",
100393
+ * "earned": 12,
100394
+ * "max": 30
100395
+ * }
100396
+ * ]
98039
100397
  * }
98040
100398
  * }
98041
100399
  * }
@@ -99179,7 +101537,7 @@ interface paths {
99179
101537
  * ],
99180
101538
  * "primary": true,
99181
101539
  * "title": "Pausar «Video testimonio · 30 s»",
99182
- * "why": "Se desgasta: en sus últimos 7 días, frente a sus 28 días anteriores, el CTR cayó 30 % o más o el costo por resultado subió 42,86 % o más (1/0,7 veces), durante 3 días seguidos. Lleva **$184.300** de gasto en los últimos 28 días y no le trae presupuestos aceptados.",
101540
+ * "why": "Se desgasta: en sus últimos 7 días, frente a sus 28 días anteriores, el CTR cayó 30 % o más o el costo por resultado subió 43 % o más, durante 3 días seguidos. Lleva **$184.300** de gasto en los últimos 28 días y no le trae presupuestos aceptados.",
99183
101541
  * "effect": "Deja de mostrarse de inmediato; puedes reactivarlo cuando quieras.",
99184
101542
  * "target": {
99185
101543
  * "level": "ad",
@@ -107582,7 +109940,9 @@ interface paths {
107582
109940
  *
107583
109941
  * `propio_sin_clasificar` (Phase 2, tenencia_source, 20270903000000) is a SUB-COUNT of `propio`, NOT a fifth bucket — the four above still sum to `total`. It is the cars nobody has ever classified (`tenencia_source=default`), provably coextensive with "sin clasificar" (a consignación can never be `default`). Measured on production 2026-08-31: 903 of 967 vehicles carried `propio` with nobody having said so — that is what this number answers, rather than leaving `propio` an unresolved warning. Opens with `GET /vehicles?active=false&tenencia=propio&tenencia_source=default`.
107584
109942
  *
107585
- * `sin_costo` (ADR 0114 §8, «Sin costo») counts the active, non-vendido cars with NO acquisition — no nota de compra, contrato de consignación or parte de pago — so their cost is unknown. Opens with `GET /vehicles?view=sin_costo`, the same predicate. A statement about the cost basis: ABSENT (not 0) for a caller without `dealership_economics:read`. Automotive-vertical only: a workspace on another vertical gets 403 here however its scopes are set.
109943
+ * `sin_costo` (ADR 0114 §8, «Sin costo») counts the active, non-vendido cars with NO acquisition — no nota de compra, contrato de consignación or parte de pago — so their cost is unknown. Opens with `GET /vehicles?view=sin_costo`, the same predicate. A statement about the cost basis: ABSENT (not 0) for a caller without `dealership_economics:read`.
109944
+ *
109945
+ * `mandato_sin_firmar` (ADR 0114 §5) counts the cars whose consignación (activa, or vendida) has an emitted mandato and no signed copy filed in the expediente. Opens with `GET /vehicles?view=mandato_sin_firmar`, the same predicate. Automotive-vertical only: a workspace on another vertical gets 403 here however its scopes are set.
107586
109946
  */
107587
109947
  get: {
107588
109948
  parameters: {
@@ -107613,6 +109973,7 @@ interface paths {
107613
109973
  * "unpublished": 7,
107614
109974
  * "stale": 0,
107615
109975
  * "sin_costo": 7,
109976
+ * "mandato_sin_firmar": 1,
107616
109977
  * "by_location": {
107617
109978
  * "b1b1b1b1-0000-4000-8000-000000000001": 3,
107618
109979
  * "b1b1b1b1-0000-4000-8000-000000000002": 1,
@@ -121517,6 +123878,178 @@ interface components {
121517
123878
  from: string;
121518
123879
  to: string;
121519
123880
  };
123881
+ AgendaResults: {
123882
+ from: string;
123883
+ to: string;
123884
+ timezone: string;
123885
+ /** Format: uuid */
123886
+ location_id: string | null;
123887
+ /**
123888
+ * @description Vocabulary: citas/pacientes, visitas/clientes, citas/clientes.
123889
+ * @enum {string}
123890
+ */
123891
+ family: "clinic" | "dealer" | "generic";
123892
+ previous_period: {
123893
+ from: string;
123894
+ to: string;
123895
+ };
123896
+ bookings: {
123897
+ /** @description Citas of the period booked by Vitrina's agent in a conversation (`source='agent'`, not a public booking page). */
123898
+ ai: number;
123899
+ /** @description Every cita of the period (blocks and holds excluded). */
123900
+ agenda_total: number;
123901
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123902
+ share_pct: number | null;
123903
+ previous: {
123904
+ ai: number;
123905
+ agenda_total: number;
123906
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123907
+ share_pct: number | null;
123908
+ };
123909
+ rule: string;
123910
+ };
123911
+ money: {
123912
+ /** @description False for a vertical with no priced citas. */
123913
+ applies: boolean;
123914
+ withheld: boolean;
123915
+ /** @description Value of the AI-booked citas whose value is known (pipeline, not cash). */
123916
+ booked_clp: number | null;
123917
+ booked_priced: number;
123918
+ /** @description AI-booked citas with no price — «sin dato». */
123919
+ booked_unpriced: number;
123920
+ /** @description CLP. `null` when unknown or when the caller lacks `clinic_money:read` (`money.withheld`). */
123921
+ agenda_clp: number | null;
123922
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123923
+ clp_share_pct: number | null;
123924
+ /** @description Cash received in the period by the patients Vitrina booked, from the day it booked them. */
123925
+ paid_clp: number | null;
123926
+ paid_patients: number | null;
123927
+ /** @description AI-booked citas with no patient to match a payment to. */
123928
+ unlinked: number;
123929
+ /** @enum {string|null} */
123930
+ regime: "mirror" | "native" | null;
123931
+ previous: {
123932
+ /** @description CLP. `null` when unknown or when the caller lacks `clinic_money:read` (`money.withheld`). */
123933
+ booked_clp: number | null;
123934
+ /** @description CLP. `null` when unknown or when the caller lacks `clinic_money:read` (`money.withheld`). */
123935
+ paid_clp: number | null;
123936
+ };
123937
+ rule_booked: string;
123938
+ rule_paid: string;
123939
+ };
123940
+ out_of_hours: {
123941
+ /** @description False when the workspace has no business hours; count/pct are then null. */
123942
+ configured: boolean;
123943
+ count: number | null;
123944
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123945
+ pct: number | null;
123946
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123947
+ previous_pct: number | null;
123948
+ /** @description AI bookings by weekday × hour of the booking, in `timezone`. Empty cells omitted. */
123949
+ heatmap: {
123950
+ /** @description 1 = Monday … 7 = Sunday. */
123951
+ weekday: number;
123952
+ hour: number;
123953
+ count: number;
123954
+ }[];
123955
+ rule: string;
123956
+ };
123957
+ autonomy: {
123958
+ no_human: number;
123959
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123960
+ pct: number | null;
123961
+ measured: number;
123962
+ unknown: number;
123963
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123964
+ previous_pct: number | null;
123965
+ rule: string;
123966
+ };
123967
+ time_to_book: {
123968
+ median_seconds: number | null;
123969
+ p95_seconds: number | null;
123970
+ p95_phrase: string | null;
123971
+ measured: number;
123972
+ unknown: number;
123973
+ previous_median_seconds: number | null;
123974
+ rule: string;
123975
+ };
123976
+ hours_returned: {
123977
+ minutes_per_booking: number;
123978
+ hours: number;
123979
+ rule: string;
123980
+ };
123981
+ recovery: {
123982
+ window_days: number;
123983
+ known_attendance: number;
123984
+ unknown_attendance: number;
123985
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123986
+ no_show_pct: number | null;
123987
+ no_show: {
123988
+ count: number;
123989
+ recovered: number;
123990
+ recovered_via_vitrina: number;
123991
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123992
+ recovered_pct: number | null;
123993
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
123994
+ via_vitrina_pct: number | null;
123995
+ /** @description Not recovered yet, still inside the 30 days. */
123996
+ pending: number;
123997
+ /** @description Missed with no identifiable patient. */
123998
+ unlinked: number;
123999
+ };
124000
+ cancelled: {
124001
+ count: number;
124002
+ recovered: number;
124003
+ recovered_via_vitrina: number;
124004
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
124005
+ recovered_pct: number | null;
124006
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
124007
+ via_vitrina_pct: number | null;
124008
+ /** @description Not recovered yet, still inside the 30 days. */
124009
+ pending: number;
124010
+ /** @description Missed with no identifiable patient. */
124011
+ unlinked: number;
124012
+ };
124013
+ rule_no_show: string;
124014
+ rule_recovered: string;
124015
+ };
124016
+ confirmation: {
124017
+ applies: boolean;
124018
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
124019
+ confirmed_attendance_pct: number | null;
124020
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
124021
+ unconfirmed_attendance_pct: number | null;
124022
+ confirmed_closed: number | null;
124023
+ unconfirmed_closed: number | null;
124024
+ rule: string;
124025
+ };
124026
+ ads: {
124027
+ /** @enum {string} */
124028
+ state: "active" | "not_active" | "unavailable";
124029
+ spend_clp: number | null;
124030
+ booked: number | null;
124031
+ attended: number | null;
124032
+ paid: number | null;
124033
+ cost_per_booked: number | null;
124034
+ cost_per_attended: number | null;
124035
+ cost_per_paid: number | null;
124036
+ rule: string;
124037
+ };
124038
+ reminders: {
124039
+ applies: boolean;
124040
+ sent: number;
124041
+ failed: number;
124042
+ /** @description Percent, one decimal. `null` — never 0 — with no denominator. */
124043
+ failed_pct: number | null;
124044
+ by_cause: {
124045
+ /** @enum {string} */
124046
+ cause: "no_patient_link" | "no_phone" | "no_channel" | "opted_out" | "template_not_approved" | "meta_payment_block" | "no_whatsapp" | "window_closed" | "template_rejected" | "send_error";
124047
+ count: number;
124048
+ }[];
124049
+ rule: string;
124050
+ };
124051
+ truncated: boolean;
124052
+ };
121520
124053
  ClinicComercialReport: {
121521
124054
  from: string;
121522
124055
  to: string;
@@ -122105,12 +124638,12 @@ interface components {
122105
124638
  /** @enum {string} */
122106
124639
  code: "OUTBOUND_BLOCKED" | "OUTBOUND_WARNING";
122107
124640
  message: string;
122108
- reasons: ("contact_blocked" | "contact_spam" | "channel_suppressed" | "scope_blocked" | "marketing_consent_missing" | "email_not_subscribed" | "outbound_hold_active" | "window_closed" | "template_missing" | "template_not_approved" | "template_unsupported" | "template_params_incomplete" | "template_category_unknown" | "template_category_mismatch" | "legal_basis_mismatch" | "no_channel_identity" | "account_disconnected" | "account_quality_red" | "past_max_lateness" | "quiet_hours" | "conversation_human_owned" | "account_quality_degraded" | "conversation_closed" | "contact_archived" | "contact_merged" | "stale_context" | "input_unresolved" | "loop_same_content" | "loop_burst")[];
124641
+ reasons: ("contact_blocked" | "contact_spam" | "channel_suppressed" | "scope_blocked" | "marketing_consent_missing" | "email_not_subscribed" | "outbound_hold_active" | "window_closed" | "template_missing" | "template_not_approved" | "template_unsupported" | "template_params_incomplete" | "template_category_unknown" | "template_category_mismatch" | "legal_basis_mismatch" | "no_channel_identity" | "account_disconnected" | "account_quality_red" | "past_max_lateness" | "quiet_hours" | "conversation_human_owned" | "account_quality_degraded" | "conversation_closed" | "contact_archived" | "contact_merged" | "stale_context" | "input_unresolved" | "loop_same_content" | "loop_burst" | "copy_address_blocked")[];
122109
124642
  hint: string;
122110
124643
  details: {
122111
124644
  reasons: {
122112
124645
  /** @enum {string} */
122113
- code: "contact_blocked" | "contact_spam" | "channel_suppressed" | "scope_blocked" | "marketing_consent_missing" | "email_not_subscribed" | "outbound_hold_active" | "window_closed" | "template_missing" | "template_not_approved" | "template_unsupported" | "template_params_incomplete" | "template_category_unknown" | "template_category_mismatch" | "legal_basis_mismatch" | "no_channel_identity" | "account_disconnected" | "account_quality_red" | "past_max_lateness" | "quiet_hours" | "conversation_human_owned" | "account_quality_degraded" | "conversation_closed" | "contact_archived" | "contact_merged" | "stale_context" | "input_unresolved" | "loop_same_content" | "loop_burst";
124646
+ code: "contact_blocked" | "contact_spam" | "channel_suppressed" | "scope_blocked" | "marketing_consent_missing" | "email_not_subscribed" | "outbound_hold_active" | "window_closed" | "template_missing" | "template_not_approved" | "template_unsupported" | "template_params_incomplete" | "template_category_unknown" | "template_category_mismatch" | "legal_basis_mismatch" | "no_channel_identity" | "account_disconnected" | "account_quality_red" | "past_max_lateness" | "quiet_hours" | "conversation_human_owned" | "account_quality_degraded" | "conversation_closed" | "contact_archived" | "contact_merged" | "stale_context" | "input_unresolved" | "loop_same_content" | "loop_burst" | "copy_address_blocked";
122114
124647
  /** @enum {string} */
122115
124648
  kind: "bloqueo" | "advertencia";
122116
124649
  hint: string;
@@ -122334,6 +124867,180 @@ interface components {
122334
124867
  */
122335
124868
  handoff_id?: string;
122336
124869
  };
124870
+ AdsReportRow: {
124871
+ spend: number | null;
124872
+ /** @description Vitrina’s own funnel: conversations each ad OPENED in the period and the stages recorded against them (a campaign / ad set sums its ads). `null` = unknown (the read failed), never 0. */
124873
+ funnel: {
124874
+ conversations: number | null;
124875
+ replied: number | null;
124876
+ appointments: number | null;
124877
+ attended: number | null;
124878
+ closes: number | null;
124879
+ };
124880
+ cost_per: {
124881
+ conversation: number | null;
124882
+ appointment: number | null;
124883
+ attended: number | null;
124884
+ close: number | null;
124885
+ };
124886
+ /** @description Payments credited to the entity (CLP). Cash only. */
124887
+ cash: number | null;
124888
+ /** @description cash ÷ spend. `null` when no payment was recorded in the period (see `cash_recorded`) — the return is unknown then, never 0×. */
124889
+ return: number | null;
124890
+ /** @description Meta’s OWN figures (its 7-day window, every sender) — never added to Vitrina’s. */
124891
+ meta: {
124892
+ conversations_started: number | null;
124893
+ cost_per_conversation: number | null;
124894
+ };
124895
+ /** @description Platform id; `null` for the unmapped bucket. */
124896
+ external_id: string | null;
124897
+ /** @enum {string} */
124898
+ level: "campaign" | "ad_set" | "ad";
124899
+ name: string;
124900
+ /** @description An ad’s ad set / an ad set’s campaign; `null` for a campaign. */
124901
+ parent: {
124902
+ external_id: string | null;
124903
+ name: string | null;
124904
+ } | null;
124905
+ thumbnail_url: string | null;
124906
+ /** @description Daily spend, oldest first; `null` unread. */
124907
+ spark: number[] | null;
124908
+ /**
124909
+ * @description Ads that opened conversations but have no row at this level yet.
124910
+ * @enum {boolean}
124911
+ */
124912
+ unmapped?: true;
124913
+ };
124914
+ AdsReport: {
124915
+ /** @enum {string} */
124916
+ level: "campaign" | "ad_set" | "ad";
124917
+ window: {
124918
+ from: string;
124919
+ to: string;
124920
+ };
124921
+ rows: components["schemas"]["AdsReportRow"][];
124922
+ /** @description «Sin anuncio»: the period’s conversations with no ad behind them. `null` = unknown. */
124923
+ tail: {
124924
+ /** @enum {string} */
124925
+ key: "website" | "portals" | "direct";
124926
+ conversations: number;
124927
+ }[] | null;
124928
+ totals: {
124929
+ spend: number | null;
124930
+ /** @description Vitrina’s own funnel: conversations each ad OPENED in the period and the stages recorded against them (a campaign / ad set sums its ads). `null` = unknown (the read failed), never 0. */
124931
+ funnel: {
124932
+ conversations: number | null;
124933
+ replied: number | null;
124934
+ appointments: number | null;
124935
+ attended: number | null;
124936
+ closes: number | null;
124937
+ };
124938
+ cost_per: {
124939
+ conversation: number | null;
124940
+ appointment: number | null;
124941
+ attended: number | null;
124942
+ close: number | null;
124943
+ };
124944
+ /** @description Payments credited to the entity (CLP). Cash only. */
124945
+ cash: number | null;
124946
+ /** @description cash ÷ spend. `null` when no payment was recorded in the period (see `cash_recorded`) — the return is unknown then, never 0×. */
124947
+ return: number | null;
124948
+ /** @description Meta’s OWN figures (its 7-day window, every sender) — never added to Vitrina’s. */
124949
+ meta: {
124950
+ conversations_started: number | null;
124951
+ cost_per_conversation: number | null;
124952
+ };
124953
+ };
124954
+ /** @description Closes credited to an ad and their recorded value — PIPELINE, never in `return`. */
124955
+ pipeline: {
124956
+ closed_count: number;
124957
+ closed_value: number;
124958
+ } | null;
124959
+ cash_recorded: boolean;
124960
+ reconciliation: {
124961
+ overview_spend: number | null;
124962
+ spend_matches: boolean | null;
124963
+ conversations_total: number | null;
124964
+ conversations_from_ads: number | null;
124965
+ conversations_without_ad: number | null;
124966
+ };
124967
+ };
124968
+ AdsAdSheet: {
124969
+ /** @description The creative and the delivery metrics; `null` when the engine read failed. */
124970
+ ad: {
124971
+ external_id: string;
124972
+ name: string;
124973
+ ad_set: {
124974
+ external_id: string | null;
124975
+ name: string | null;
124976
+ } | null;
124977
+ campaign: {
124978
+ external_id: string;
124979
+ } | null;
124980
+ thumbnail_url: string | null;
124981
+ title: string | null;
124982
+ body: string | null;
124983
+ has_video: boolean;
124984
+ spend: number | null;
124985
+ impressions: number;
124986
+ clicks: number;
124987
+ ctr: number;
124988
+ cpm: number;
124989
+ cpc: number;
124990
+ cash_count: number;
124991
+ cash_value: number;
124992
+ meta_conversations_started: number | null;
124993
+ } | null;
124994
+ window: {
124995
+ from: string;
124996
+ to: string;
124997
+ };
124998
+ /** @description The same figures as the Reporte row for this ad. */
124999
+ row: {
125000
+ spend: number | null;
125001
+ /** @description Vitrina’s own funnel: conversations each ad OPENED in the period and the stages recorded against them (a campaign / ad set sums its ads). `null` = unknown (the read failed), never 0. */
125002
+ funnel: {
125003
+ conversations: number | null;
125004
+ replied: number | null;
125005
+ appointments: number | null;
125006
+ attended: number | null;
125007
+ closes: number | null;
125008
+ };
125009
+ cost_per: {
125010
+ conversation: number | null;
125011
+ appointment: number | null;
125012
+ attended: number | null;
125013
+ close: number | null;
125014
+ };
125015
+ /** @description Payments credited to the entity (CLP). Cash only. */
125016
+ cash: number | null;
125017
+ /** @description cash ÷ spend. `null` when no payment was recorded in the period (see `cash_recorded`) — the return is unknown then, never 0×. */
125018
+ return: number | null;
125019
+ /** @description Meta’s OWN figures (its 7-day window, every sender) — never added to Vitrina’s. */
125020
+ meta: {
125021
+ conversations_started: number | null;
125022
+ cost_per_conversation: number | null;
125023
+ };
125024
+ };
125025
+ cash_recorded: boolean;
125026
+ /** @description The conversations this ad opened, newest first. Healthcare: always initials. Elsewhere a name only with `contacts:read`. No export. */
125027
+ people: {
125028
+ /** Format: uuid */
125029
+ conversation_id: string;
125030
+ /** Format: uuid */
125031
+ contact_id: string | null;
125032
+ /** @description Initials, or the name where allowed. Never a phone or an e-mail. */
125033
+ label: string;
125034
+ masked: boolean;
125035
+ stage: string | null;
125036
+ stage_at: string | null;
125037
+ opened_at: string;
125038
+ value: number | null;
125039
+ }[];
125040
+ people_more: boolean;
125041
+ /** @description The caller lacks `contacts:read`: `people` is empty on purpose. */
125042
+ people_hidden: boolean;
125043
+ };
122337
125044
  AdsOverviewDay: {
122338
125045
  date: string;
122339
125046
  /** @description `null` exactly when the engine could not scope spend. */
@@ -122345,6 +125052,21 @@ interface components {
122345
125052
  /** @description `true` on the day still running (today, America/Santiago): end the solid line before it. */
122346
125053
  partial: boolean;
122347
125054
  };
125055
+ AdsGap: {
125056
+ /** @description First day with missing data, YYYY-MM-DD. */
125057
+ from: string;
125058
+ /** @description Last day with missing data, YYYY-MM-DD; `null` = still ongoing. */
125059
+ to: string | null;
125060
+ /**
125061
+ * @description What broke: `meta_disconnected` / `meta_stale` (the ad account read), `tag_silent` (the site tag stopped reporting), `capi_failing` (the Conversions API sends), `whatsapp_disconnected`, `engine_facts_missing` (clinic payments/plans not reaching the attribution).
125062
+ * @enum {string}
125063
+ */
125064
+ cause: "meta_disconnected" | "meta_stale" | "tag_silent" | "capi_failing" | "whatsapp_disconnected" | "engine_facts_missing";
125065
+ /** @description The figures UNKNOWN inside the gap: draw them as missing (a break in the line, «sin datos»), never as 0. Empty = nothing Vitrina shows is blanked; the window is annotated only. */
125066
+ metrics: ("spend" | "conversations" | "outcomes")[];
125067
+ /** Format: uuid */
125068
+ incident_id: string;
125069
+ };
122348
125070
  AdsOverview: {
122349
125071
  current: {
122350
125072
  spend: number | null;
@@ -122371,6 +125093,11 @@ interface components {
122371
125093
  outcome_counts: {
122372
125094
  [key: string]: number;
122373
125095
  };
125096
+ /** @description PIPELINE, never cash (not in `revenue` / `roas`): the period’s closes (`closed_won` — a clinic’s accepted plans, a dealer’s closed sales) that the attribution engine credited to an ad, with the value Vitrina recorded for them (CLP). On `current` only. `null` = unknown (the credit is still warming); absent on `previous` and on the sample. */
125097
+ attributed_pipeline?: {
125098
+ closed_count: number;
125099
+ closed_value: number;
125100
+ } | null;
122374
125101
  };
122375
125102
  previous: {
122376
125103
  spend: number | null;
@@ -122397,11 +125124,54 @@ interface components {
122397
125124
  outcome_counts: {
122398
125125
  [key: string]: number;
122399
125126
  };
125127
+ /** @description PIPELINE, never cash (not in `revenue` / `roas`): the period’s closes (`closed_won` — a clinic’s accepted plans, a dealer’s closed sales) that the attribution engine credited to an ad, with the value Vitrina recorded for them (CLP). On `current` only. `null` = unknown (the credit is still warming); absent on `previous` and on the sample. */
125128
+ attributed_pipeline?: {
125129
+ closed_count: number;
125130
+ closed_value: number;
125131
+ } | null;
122400
125132
  };
122401
125133
  /** @description `grain=day` only: every day of the window, oldest first. */
122402
125134
  days?: components["schemas"]["AdsOverviewDay"][];
122403
125135
  /** @description `grain=day` only: every day of the previous window of equal length. */
122404
125136
  previous_days?: components["schemas"]["AdsOverviewDay"][];
125137
+ /** @description Measurement gaps overlapping the window (W1.1). Days inside a gap whose `metrics` list a figure carry NO measured value for it — the engine may report 0 there; render «sin datos», never the 0. */
125138
+ gaps: components["schemas"]["AdsGap"][];
125139
+ };
125140
+ AdsMeasurementIncident: {
125141
+ /** Format: uuid */
125142
+ id: string;
125143
+ /** @enum {string} */
125144
+ cause: "meta_disconnected" | "meta_stale" | "tag_silent" | "capi_failing" | "whatsapp_disconnected" | "engine_facts_missing";
125145
+ /** @description «Meta Ads desconectado». */
125146
+ label: string;
125147
+ /** @description «Tus anuncios de Meta dejaron de medirse el 12 sep». */
125148
+ sentence: string;
125149
+ /** @description The one primary action. */
125150
+ action: {
125151
+ /** @description «Reconectar Meta». */
125152
+ label: string;
125153
+ /** @description Workspace-relative path of the ONE fix, e.g. `/anuncios/activar?paso=meta`. */
125154
+ path: string;
125155
+ };
125156
+ /** @description When the data stopped (ISO instant). */
125157
+ since: string;
125158
+ /** @description When the watchdog opened it (ISO). */
125159
+ opened_at: string;
125160
+ resolved_at: string | null;
125161
+ /**
125162
+ * @description `reconnected` — a member fixed it; `recovered` — the leg came back on its own; `withdrawn` — it was switched off on purpose.
125163
+ * @enum {string|null}
125164
+ */
125165
+ resolution: "reconnected" | "recovered" | "withdrawn" | null;
125166
+ /** @description The member who fixed it. `null` when it recovered on its own, or when the caller lacks `memberships:read`. */
125167
+ resolved_by_name: string | null;
125168
+ metrics: ("spend" | "conversations" | "outcomes")[];
125169
+ };
125170
+ AdsMeasurement: {
125171
+ /** @description Open incidents, oldest first — the banner. */
125172
+ open: components["schemas"]["AdsMeasurementIncident"][];
125173
+ /** @description Incidents resolved in the last 14 days, newest first. */
125174
+ recent: components["schemas"]["AdsMeasurementIncident"][];
122405
125175
  };
122406
125176
  /** @description Present on a conversational row: a message-only objective (`MESSAGES`), or conversations the platform reports, or conversations Vitrina counts. Also present with `data_complete: false` (figures `null`) when a read failed on a row that may be conversational (its objective unknown or in the messaging family) in a workspace with ad-opened conversations. ABSENT otherwise — never a row of zeros, never partial counts. */
122407
125177
  AdsConversational: {
@@ -122436,7 +125206,7 @@ interface components {
122436
125206
  campaign_name: string;
122437
125207
  campaign_external_id: string | null;
122438
125208
  spend: number;
122439
- /** @description Conversions the attribution engine credits to this campaign over the period, under `model` — every outcome kind it counts, not only closes; a multi-touch model splits one conversion across campaigns. Not the population of `closed_outcome_count`. */
125209
+ /** @description Conversions the attribution engine credits to this campaign over the period, under `model`. Today the engine counts CASH conversions only (payments; `revenue_type = cash`) — a lead, a cita or an accepted plan without a payment is not in it, so a workspace with no payments recorded reads 0 on every row. Not the population of `/ads/overview` `attributed_outcomes` (every kind) nor of `closed_outcome_count`. */
122440
125210
  outcome_count: number;
122441
125211
  outcome_value: number;
122442
125212
  roas: number;
@@ -122460,6 +125230,8 @@ interface components {
122460
125230
  }[] | null;
122461
125231
  conversational?: components["schemas"]["AdsConversational"];
122462
125232
  }[];
125233
+ /** @description Measurement gaps overlapping the window (W1.1). Days inside a gap whose `metrics` list a figure carry NO measured value for it — the engine may report 0 there; render «sin datos», never the 0. */
125234
+ gaps: components["schemas"]["AdsGap"][];
122463
125235
  };
122464
125236
  AdsAttributedSales: {
122465
125237
  data: {
@@ -122526,6 +125298,22 @@ interface components {
122526
125298
  conversational?: components["schemas"]["AdsConversational"] & unknown;
122527
125299
  }[];
122528
125300
  };
125301
+ AdsSignalComponent: {
125302
+ /** @enum {string} */
125303
+ key: "meta" | "origin" | "site_tag";
125304
+ /** @enum {string} */
125305
+ status: "ok" | "partial" | "missing" | "skipped" | "unknown";
125306
+ /** @description Points earned; 0 when `skipped` or `unknown`. */
125307
+ earned: number;
125308
+ /** @description The component’s weight (meta 30, origin 40, site_tag 30); it counts toward the total unless the status is `skipped` or `unknown`. */
125309
+ max: number;
125310
+ };
125311
+ /** @description Vitrina’s own signal score with partial credit: the Meta connection, the share of results with their origin identified (proportional — the same population as `outcomes_coverage`) and the website tag (live full, sparse partial, never reported 0; skipped when the workspace has no website). Not the engine’s `trust.instrumentation.score`, which grades a web checkout only. */
125312
+ AdsSignalsScore: {
125313
+ /** @description Salud’s «Puntaje de señales», 0–100: the earned share of the components that could be judged. `null` when none could. */
125314
+ score: number | null;
125315
+ components: components["schemas"]["AdsSignalComponent"][];
125316
+ };
122529
125317
  AdsHealth: {
122530
125318
  trust: {
122531
125319
  model: string;
@@ -122590,6 +125378,7 @@ interface components {
122590
125378
  attributed_outcomes: number;
122591
125379
  coverage_percent: number;
122592
125380
  } | null;
125381
+ signals: components["schemas"]["AdsSignalsScore"];
122593
125382
  };
122594
125383
  AdsFact: {
122595
125384
  /** @description Stable fact key (`roas`, `best_campaign_name`, …) — a vocabulary name, not a resource id. */