@vitrina/api 13.0.0 → 13.2.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.
- package/dist/index.d.cts +3252 -286
- package/dist/index.d.ts +3252 -286
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2058,6 +2058,10 @@ interface paths {
|
|
|
2058
2058
|
treatment_price?: "unset" | "first_ask" | "never";
|
|
2059
2059
|
/** @description «Ofrecer lista de espera si la primera hora está a más de 7 días» (#3314). Default false. */
|
|
2060
2060
|
far_slot_waitlist?: boolean;
|
|
2061
|
+
/** @description «Dolor: ofrecer las primeras horas de hoy o mañana» (D72). A patient in pain is offered today's / tomorrow's first slots in the same turn; a handoff becomes a heads-up to reception, not the answer. Default false; true for the agent a new clinic's onboarding creates. */
|
|
2062
|
+
urgency_slots?: boolean;
|
|
2063
|
+
/** @description «Especialista a más de 7 días: ofrecer también una evaluación general esta semana» (D74). `find_slots` then also reports the clinic's general evaluation slots of the next 7 days. Default false. */
|
|
2064
|
+
specialist_fallback?: boolean;
|
|
2061
2065
|
};
|
|
2062
2066
|
/** @description The `draft_version` version you last read (the `X-Config-Version` response header, or the version field in the body). If it is no longer current the write is refused with 409 `VERSION_CONFLICT` and nothing is written; the error carries the current version and a diff hint. Optional for backward compatibility (an omitted value is accepted and logged), but send it: without it two editors silently overwrite each other. The `If-Match` header is accepted as an alternative. */
|
|
2063
2067
|
expected_version?: number | null;
|
|
@@ -2241,7 +2245,7 @@ interface paths {
|
|
|
2241
2245
|
};
|
|
2242
2246
|
/**
|
|
2243
2247
|
* Read the agent’s behaviour policies
|
|
2244
|
-
* @description Per-agent switches that change what the agent says (#3312/#3314): `treatment_price` (`unset` | `first_ask` | `never`, healthcare) and `far_slot_waitlist
|
|
2248
|
+
* @description Per-agent switches that change what the agent says (#3312/#3314): `treatment_price` (`unset` | `first_ask` | `never`, healthcare) and `far_slot_waitlist`, `urgency_slots` (D72) and `specialist_fallback` (D74). `live` is what runs today, `draft` what is staged (null = nothing staged). Every default is the agent’s behaviour before policies existed: nothing is added to its prompt while a policy is unset. `price_policy_conflicts` lists lines of the agent’s own instructions (draft when staged) and active skills that already state a price rule, so a client can reconcile them before publishing. Change them with `PUT /ai-agents/{id}/draft` (`behavior_policies`) and `POST /ai-agents/{id}/publish`.
|
|
2245
2249
|
*/
|
|
2246
2250
|
get: {
|
|
2247
2251
|
parameters: {
|
|
@@ -2265,11 +2269,15 @@ interface paths {
|
|
|
2265
2269
|
* "data": {
|
|
2266
2270
|
* "live": {
|
|
2267
2271
|
* "treatment_price": "unset",
|
|
2268
|
-
* "far_slot_waitlist": false
|
|
2272
|
+
* "far_slot_waitlist": false,
|
|
2273
|
+
* "urgency_slots": false,
|
|
2274
|
+
* "specialist_fallback": false
|
|
2269
2275
|
* },
|
|
2270
2276
|
* "draft": {
|
|
2271
2277
|
* "treatment_price": "first_ask",
|
|
2272
|
-
* "far_slot_waitlist": false
|
|
2278
|
+
* "far_slot_waitlist": false,
|
|
2279
|
+
* "urgency_slots": true,
|
|
2280
|
+
* "specialist_fallback": false
|
|
2273
2281
|
* },
|
|
2274
2282
|
* "price_policy_conflicts": [
|
|
2275
2283
|
* {
|
|
@@ -2291,6 +2299,10 @@ interface paths {
|
|
|
2291
2299
|
treatment_price: "unset" | "first_ask" | "never";
|
|
2292
2300
|
/** @description «Ofrecer lista de espera si la primera hora está a más de 7 días» (#3314). Default false. */
|
|
2293
2301
|
far_slot_waitlist: boolean;
|
|
2302
|
+
/** @description «Dolor: ofrecer las primeras horas de hoy o mañana» (D72). A patient in pain is offered today's / tomorrow's first slots in the same turn; a handoff becomes a heads-up to reception, not the answer. Default false; true for the agent a new clinic's onboarding creates. */
|
|
2303
|
+
urgency_slots: boolean;
|
|
2304
|
+
/** @description «Especialista a más de 7 días: ofrecer también una evaluación general esta semana» (D74). `find_slots` then also reports the clinic's general evaluation slots of the next 7 days. Default false. */
|
|
2305
|
+
specialist_fallback: boolean;
|
|
2294
2306
|
};
|
|
2295
2307
|
draft: {
|
|
2296
2308
|
/**
|
|
@@ -2300,6 +2312,10 @@ interface paths {
|
|
|
2300
2312
|
treatment_price: "unset" | "first_ask" | "never";
|
|
2301
2313
|
/** @description «Ofrecer lista de espera si la primera hora está a más de 7 días» (#3314). Default false. */
|
|
2302
2314
|
far_slot_waitlist: boolean;
|
|
2315
|
+
/** @description «Dolor: ofrecer las primeras horas de hoy o mañana» (D72). A patient in pain is offered today's / tomorrow's first slots in the same turn; a handoff becomes a heads-up to reception, not the answer. Default false; true for the agent a new clinic's onboarding creates. */
|
|
2316
|
+
urgency_slots: boolean;
|
|
2317
|
+
/** @description «Especialista a más de 7 días: ofrecer también una evaluación general esta semana» (D74). `find_slots` then also reports the clinic's general evaluation slots of the next 7 days. Default false. */
|
|
2318
|
+
specialist_fallback: boolean;
|
|
2303
2319
|
} | null;
|
|
2304
2320
|
price_policy_conflicts: {
|
|
2305
2321
|
/** @enum {string} */
|
|
@@ -59389,6 +59405,1132 @@ interface paths {
|
|
|
59389
59405
|
patch?: never;
|
|
59390
59406
|
trace?: never;
|
|
59391
59407
|
};
|
|
59408
|
+
"/clinic/budget-followups/today": {
|
|
59409
|
+
parameters: {
|
|
59410
|
+
query?: never;
|
|
59411
|
+
header?: never;
|
|
59412
|
+
path?: never;
|
|
59413
|
+
cookie?: never;
|
|
59414
|
+
};
|
|
59415
|
+
/**
|
|
59416
|
+
* «Llamar hoy»: unaccepted presupuestos to follow up today
|
|
59417
|
+
* @description The clinic's follow-up of unaccepted presupuestos, one row per LINEAGE (a re-issue never restarts it). A presupuesto is on the list on the clinic day after it was first sent, and again on day 7 and day 21 (`step` 1/2/3), until it is accepted, rejected, voided, expires (60 days, 90 for ortodoncia / implantología), a cita is booked, the patient answers a touch, or reception taps «Aceptó» / «No quiere». Rows carry what reception needs to call (patient, phone, items, total, professional) and the day's logged `outcome`. When no outcome was logged and nobody at the clinic wrote to the patient since the step opened, a WhatsApp `touch` is proposed at 17:00 clinic time (11:00 when `call_list` is off) — always for a person's approval (`touch.action_id` goes to `POST /outbound/approvals/{id}/approve`); at most three per lineage; never twice a day; never a price or a discount. `counts.unlogged` is «n sin registrar». `summary` covers the lineages issued in the last 30 days: followed up vs never contacted. `template` says whether the WhatsApp template for touches outside the 24 h window is approved. Each row carries the patient's `origin` (Meta with the ad, or Orgánico: the attribution Vitrina Ads reports); narrow the list with `origin=meta|organic|unknown` and `origin_ad_id` — `counts` follow the narrowing, `summary` does not. Requires `clinic:read`.
|
|
59418
|
+
*
|
|
59419
|
+
* **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`.
|
|
59420
|
+
*/
|
|
59421
|
+
get: {
|
|
59422
|
+
parameters: {
|
|
59423
|
+
query?: {
|
|
59424
|
+
/** @description Origen of the patient: `meta` (came from a Meta ad), `organic` (a linked contact with no ad touch) or `unknown` («Sin dato»: no linked contact). Same attribution as Vitrina Ads' people from ads. */
|
|
59425
|
+
origin?: "meta" | "organic" | "unknown";
|
|
59426
|
+
/** @description Narrow `origin=meta` to one Meta ad (its platform ad id). */
|
|
59427
|
+
origin_ad_id?: string;
|
|
59428
|
+
};
|
|
59429
|
+
header?: never;
|
|
59430
|
+
path?: never;
|
|
59431
|
+
cookie?: never;
|
|
59432
|
+
};
|
|
59433
|
+
requestBody?: never;
|
|
59434
|
+
responses: {
|
|
59435
|
+
/** @description Today's follow-up list */
|
|
59436
|
+
200: {
|
|
59437
|
+
headers: {
|
|
59438
|
+
[name: string]: unknown;
|
|
59439
|
+
};
|
|
59440
|
+
content: {
|
|
59441
|
+
/**
|
|
59442
|
+
* @example {
|
|
59443
|
+
* "data": {
|
|
59444
|
+
* "today": "2026-10-09",
|
|
59445
|
+
* "call_list": true,
|
|
59446
|
+
* "template": {
|
|
59447
|
+
* "name": "seguimiento_presupuesto",
|
|
59448
|
+
* "status": "approved",
|
|
59449
|
+
* "whatsapp_connected": true
|
|
59450
|
+
* },
|
|
59451
|
+
* "counts": {
|
|
59452
|
+
* "to_call": 1,
|
|
59453
|
+
* "logged": 0,
|
|
59454
|
+
* "unlogged": 1,
|
|
59455
|
+
* "by_priority": {
|
|
59456
|
+
* "P1": 1,
|
|
59457
|
+
* "P2": 2,
|
|
59458
|
+
* "P3": 3,
|
|
59459
|
+
* "P4": 4
|
|
59460
|
+
* },
|
|
59461
|
+
* "awaiting_approval": 0
|
|
59462
|
+
* },
|
|
59463
|
+
* "viewer": {
|
|
59464
|
+
* "may_log": true,
|
|
59465
|
+
* "may_approve": true,
|
|
59466
|
+
* "may_configure": false
|
|
59467
|
+
* },
|
|
59468
|
+
* "money_visible": true,
|
|
59469
|
+
* "rows": [
|
|
59470
|
+
* {
|
|
59471
|
+
* "id": "7b7b7b7b-0000-4000-8000-000000000001",
|
|
59472
|
+
* "lineage_id": "7c7c7c7c-0000-4000-8000-000000000001",
|
|
59473
|
+
* "source": "native",
|
|
59474
|
+
* "budget_id": "7d7d7d7d-0000-4000-8000-000000000001",
|
|
59475
|
+
* "mirror_plan_id": null,
|
|
59476
|
+
* "vendor": null,
|
|
59477
|
+
* "budget_display_id": "P-0412",
|
|
59478
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
59479
|
+
* "phone": "+56960000001",
|
|
59480
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
59481
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
59482
|
+
* "conversation_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
59483
|
+
* "linea": {
|
|
59484
|
+
* "id": "d1d1d1d1-0000-4000-8000-000000000001",
|
|
59485
|
+
* "nombre": "Implantes"
|
|
59486
|
+
* },
|
|
59487
|
+
* "origin": {
|
|
59488
|
+
* "kind": "organic",
|
|
59489
|
+
* "label": "Orgánico",
|
|
59490
|
+
* "ad_id": null,
|
|
59491
|
+
* "ad_name": null,
|
|
59492
|
+
* "ad_set_name": null,
|
|
59493
|
+
* "campaign_name": null,
|
|
59494
|
+
* "first_touch_at": null,
|
|
59495
|
+
* "via": null
|
|
59496
|
+
* },
|
|
59497
|
+
* "professional_name": "Dra. Ana Soto",
|
|
59498
|
+
* "items": [
|
|
59499
|
+
* "Implante unitario"
|
|
59500
|
+
* ],
|
|
59501
|
+
* "item_count": 1,
|
|
59502
|
+
* "total_clp": 890000,
|
|
59503
|
+
* "issued_on": "2026-10-08",
|
|
59504
|
+
* "issued_label": "jueves 8 de octubre",
|
|
59505
|
+
* "days_since_issue": 1,
|
|
59506
|
+
* "step": 1,
|
|
59507
|
+
* "status": "active",
|
|
59508
|
+
* "stop_reason": null,
|
|
59509
|
+
* "touches_sent": 0,
|
|
59510
|
+
* "promised": false,
|
|
59511
|
+
* "outcome": null,
|
|
59512
|
+
* "touch": null
|
|
59513
|
+
* }
|
|
59514
|
+
* ],
|
|
59515
|
+
* "summary": {
|
|
59516
|
+
* "from": "2026-09-10",
|
|
59517
|
+
* "to": "2026-10-09",
|
|
59518
|
+
* "lineages": 12,
|
|
59519
|
+
* "followed_up": 9,
|
|
59520
|
+
* "never_contacted": 3,
|
|
59521
|
+
* "in_progress": 4,
|
|
59522
|
+
* "closed_after_followup": 5
|
|
59523
|
+
* }
|
|
59524
|
+
* }
|
|
59525
|
+
* }
|
|
59526
|
+
*/
|
|
59527
|
+
"application/json": {
|
|
59528
|
+
data: {
|
|
59529
|
+
today: string;
|
|
59530
|
+
call_list: boolean;
|
|
59531
|
+
template: {
|
|
59532
|
+
name: string;
|
|
59533
|
+
/** @enum {string} */
|
|
59534
|
+
status: "approved" | "pending" | "rejected" | "missing" | "wrong_category";
|
|
59535
|
+
whatsapp_connected: boolean;
|
|
59536
|
+
};
|
|
59537
|
+
counts: {
|
|
59538
|
+
to_call: number;
|
|
59539
|
+
logged: number;
|
|
59540
|
+
/** @description «n sin registrar» */
|
|
59541
|
+
unlogged: number;
|
|
59542
|
+
/** @description Leads per Prioridad de llamada, whole section. */
|
|
59543
|
+
by_priority: {
|
|
59544
|
+
P1: number;
|
|
59545
|
+
P2: number;
|
|
59546
|
+
P3: number;
|
|
59547
|
+
P4: number;
|
|
59548
|
+
};
|
|
59549
|
+
awaiting_approval: number;
|
|
59550
|
+
};
|
|
59551
|
+
viewer: {
|
|
59552
|
+
may_log: boolean;
|
|
59553
|
+
may_approve: boolean;
|
|
59554
|
+
may_configure: boolean;
|
|
59555
|
+
};
|
|
59556
|
+
/** @description Whether rows carry items and totals (`clinic_money:read`). */
|
|
59557
|
+
money_visible: boolean;
|
|
59558
|
+
rows: {
|
|
59559
|
+
/** Format: uuid */
|
|
59560
|
+
id: string;
|
|
59561
|
+
/** Format: uuid */
|
|
59562
|
+
lineage_id: string;
|
|
59563
|
+
/**
|
|
59564
|
+
* @description `native`: a Vitrina presupuesto. `mirror`: a Dentalink / Medilink plan copied by the espejo de ingresos — it is accepted in the vendor, so there is no Vitrina accept link.
|
|
59565
|
+
* @enum {string}
|
|
59566
|
+
*/
|
|
59567
|
+
source: "native" | "mirror";
|
|
59568
|
+
/**
|
|
59569
|
+
* Format: uuid
|
|
59570
|
+
* @description Native rows only; null on a mirror row.
|
|
59571
|
+
*/
|
|
59572
|
+
budget_id: string | null;
|
|
59573
|
+
/**
|
|
59574
|
+
* Format: uuid
|
|
59575
|
+
* @description Mirror rows only: the `clinic_mirror_plan` the row follows.
|
|
59576
|
+
*/
|
|
59577
|
+
mirror_plan_id: string | null;
|
|
59578
|
+
/**
|
|
59579
|
+
* @description Mirror rows only: where the plan lives («Plan en Dentalink»).
|
|
59580
|
+
* @enum {string|null}
|
|
59581
|
+
*/
|
|
59582
|
+
vendor: "dentalink" | "medilink" | null;
|
|
59583
|
+
/** @description The folio, or the vendor plan number on a mirror row. */
|
|
59584
|
+
budget_display_id: string | null;
|
|
59585
|
+
patient_name: string | null;
|
|
59586
|
+
phone: string | null;
|
|
59587
|
+
/** Format: uuid */
|
|
59588
|
+
contact_id: string | null;
|
|
59589
|
+
/** Format: uuid */
|
|
59590
|
+
clinic_patient_id: string | null;
|
|
59591
|
+
/** Format: uuid */
|
|
59592
|
+
conversation_id: string | null;
|
|
59593
|
+
/** @description The patient's Línea (#4008): its open lead's, else its latest. */
|
|
59594
|
+
linea: {
|
|
59595
|
+
/** Format: uuid */
|
|
59596
|
+
id: string;
|
|
59597
|
+
nombre: string;
|
|
59598
|
+
} | null;
|
|
59599
|
+
/** @description The patient's Origen (null only if the read failed). */
|
|
59600
|
+
origin: {
|
|
59601
|
+
/**
|
|
59602
|
+
* @description `meta`: came from a Meta ad. `organic`: a linked contact with no ad touch. `unknown` («Sin dato»): no contact is linked to the person, so no ad touch can be read.
|
|
59603
|
+
* @enum {string}
|
|
59604
|
+
*/
|
|
59605
|
+
kind: "meta" | "organic" | "unknown";
|
|
59606
|
+
/** @description «Meta · Implantes octubre», «Meta» (ad name unknown), «Orgánico». */
|
|
59607
|
+
label: string;
|
|
59608
|
+
/** @description Meta only: the platform ad id (what `origin_ad_id` takes). */
|
|
59609
|
+
ad_id: string | null;
|
|
59610
|
+
ad_name: string | null;
|
|
59611
|
+
ad_set_name: string | null;
|
|
59612
|
+
campaign_name: string | null;
|
|
59613
|
+
/** @description Meta only: when they first wrote through the ad (or came back). */
|
|
59614
|
+
first_touch_at: string | null;
|
|
59615
|
+
/**
|
|
59616
|
+
* @description `first_message`: the first thing they wrote came from the ad. `returned`: they were already writing and came back through one. Both count as people from ads.
|
|
59617
|
+
* @enum {string|null}
|
|
59618
|
+
*/
|
|
59619
|
+
via: "first_message" | "returned" | null;
|
|
59620
|
+
} | null;
|
|
59621
|
+
professional_name: string | null;
|
|
59622
|
+
/** @description The first three item labels. */
|
|
59623
|
+
items: string[];
|
|
59624
|
+
item_count: number;
|
|
59625
|
+
/** @description `null` (and `items` empty) for a caller without `clinic_money:read`. */
|
|
59626
|
+
total_clp: number | null;
|
|
59627
|
+
issued_on: string;
|
|
59628
|
+
/** @description «lunes 21 de septiembre» */
|
|
59629
|
+
issued_label: string;
|
|
59630
|
+
days_since_issue: number;
|
|
59631
|
+
/** @description The step that falls today: 1 = día siguiente, 2 = día 7, 3 = día 21. */
|
|
59632
|
+
step: 1 | 2 | 3 | null;
|
|
59633
|
+
/** @enum {string} */
|
|
59634
|
+
status: "active" | "stopped";
|
|
59635
|
+
/** @enum {string|null} */
|
|
59636
|
+
stop_reason: "accepted" | "rejected" | "voided" | "expired" | "cita_booked" | "call_accepted" | "call_declined" | "replied" | "opted_out" | "no_marketing_consent" | "ladder_done" | "plan_paid" | null;
|
|
59637
|
+
touches_sent: number;
|
|
59638
|
+
promised: boolean;
|
|
59639
|
+
outcome: {
|
|
59640
|
+
/** @enum {string} */
|
|
59641
|
+
value: "accepted" | "declined" | "thinking" | "no_answer";
|
|
59642
|
+
at: string;
|
|
59643
|
+
} | null;
|
|
59644
|
+
touch: {
|
|
59645
|
+
/** @enum {string} */
|
|
59646
|
+
state: "awaiting_approval" | "scheduled" | "sent" | "skipped" | "refused" | "expired" | "failed";
|
|
59647
|
+
/** Format: uuid */
|
|
59648
|
+
action_id: string | null;
|
|
59649
|
+
message: string | null;
|
|
59650
|
+
reason: string | null;
|
|
59651
|
+
} | null;
|
|
59652
|
+
}[];
|
|
59653
|
+
summary: {
|
|
59654
|
+
from: string;
|
|
59655
|
+
to: string;
|
|
59656
|
+
lineages: number;
|
|
59657
|
+
followed_up: number;
|
|
59658
|
+
never_contacted: number;
|
|
59659
|
+
in_progress: number;
|
|
59660
|
+
closed_after_followup: number;
|
|
59661
|
+
};
|
|
59662
|
+
};
|
|
59663
|
+
};
|
|
59664
|
+
};
|
|
59665
|
+
};
|
|
59666
|
+
/** @description Validation error */
|
|
59667
|
+
400: {
|
|
59668
|
+
headers: {
|
|
59669
|
+
[name: string]: unknown;
|
|
59670
|
+
};
|
|
59671
|
+
content: {
|
|
59672
|
+
"application/json": components["schemas"]["Error"];
|
|
59673
|
+
};
|
|
59674
|
+
};
|
|
59675
|
+
/** @description Unauthorized */
|
|
59676
|
+
401: {
|
|
59677
|
+
headers: {
|
|
59678
|
+
[name: string]: unknown;
|
|
59679
|
+
};
|
|
59680
|
+
content: {
|
|
59681
|
+
"application/json": components["schemas"]["Error"];
|
|
59682
|
+
};
|
|
59683
|
+
};
|
|
59684
|
+
/** @description Forbidden */
|
|
59685
|
+
403: {
|
|
59686
|
+
headers: {
|
|
59687
|
+
[name: string]: unknown;
|
|
59688
|
+
};
|
|
59689
|
+
content: {
|
|
59690
|
+
"application/json": components["schemas"]["Error"];
|
|
59691
|
+
};
|
|
59692
|
+
};
|
|
59693
|
+
/** @description Not found */
|
|
59694
|
+
404: {
|
|
59695
|
+
headers: {
|
|
59696
|
+
[name: string]: unknown;
|
|
59697
|
+
};
|
|
59698
|
+
content: {
|
|
59699
|
+
"application/json": components["schemas"]["Error"];
|
|
59700
|
+
};
|
|
59701
|
+
};
|
|
59702
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
59703
|
+
409: {
|
|
59704
|
+
headers: {
|
|
59705
|
+
[name: string]: unknown;
|
|
59706
|
+
};
|
|
59707
|
+
content: {
|
|
59708
|
+
"application/json": components["schemas"]["Error"];
|
|
59709
|
+
};
|
|
59710
|
+
};
|
|
59711
|
+
/** @description Rate limited */
|
|
59712
|
+
429: {
|
|
59713
|
+
headers: {
|
|
59714
|
+
[name: string]: unknown;
|
|
59715
|
+
};
|
|
59716
|
+
content: {
|
|
59717
|
+
"application/json": components["schemas"]["Error"];
|
|
59718
|
+
};
|
|
59719
|
+
};
|
|
59720
|
+
};
|
|
59721
|
+
};
|
|
59722
|
+
put?: never;
|
|
59723
|
+
post?: never;
|
|
59724
|
+
delete?: never;
|
|
59725
|
+
options?: never;
|
|
59726
|
+
head?: never;
|
|
59727
|
+
patch?: never;
|
|
59728
|
+
trace?: never;
|
|
59729
|
+
};
|
|
59730
|
+
"/clinic/budget-followups/{id}/outcome": {
|
|
59731
|
+
parameters: {
|
|
59732
|
+
query?: never;
|
|
59733
|
+
header?: never;
|
|
59734
|
+
path?: never;
|
|
59735
|
+
cookie?: never;
|
|
59736
|
+
};
|
|
59737
|
+
get?: never;
|
|
59738
|
+
put?: never;
|
|
59739
|
+
/**
|
|
59740
|
+
* Log the outcome of a follow-up call
|
|
59741
|
+
* @description One tap of reception, ledgered against the lineage. `accepted` and `declined` stop the follow-up (and cancel a touch waiting for approval); `thinking` skips today's WhatsApp; `no_answer` lets it go out this afternoon. A later tap on the same day supersedes the earlier one — a stop tapped by mistake is undone by tapping another outcome. Never accepts the presupuesto itself. Requires `clinic:write`.
|
|
59742
|
+
*
|
|
59743
|
+
* **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`.
|
|
59744
|
+
*/
|
|
59745
|
+
post: {
|
|
59746
|
+
parameters: {
|
|
59747
|
+
query?: never;
|
|
59748
|
+
header?: {
|
|
59749
|
+
/** @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. */
|
|
59750
|
+
"Idempotency-Key"?: string;
|
|
59751
|
+
};
|
|
59752
|
+
path: {
|
|
59753
|
+
id: string;
|
|
59754
|
+
};
|
|
59755
|
+
cookie?: never;
|
|
59756
|
+
};
|
|
59757
|
+
requestBody?: {
|
|
59758
|
+
content: {
|
|
59759
|
+
/**
|
|
59760
|
+
* @example {
|
|
59761
|
+
* "outcome": "thinking"
|
|
59762
|
+
* }
|
|
59763
|
+
*/
|
|
59764
|
+
"application/json": {
|
|
59765
|
+
/**
|
|
59766
|
+
* @description `accepted` «Aceptó» and `declined` «No quiere» stop the follow-up; `thinking` «Lo va a pensar» skips today's WhatsApp; `no_answer` «No contestó» sends it this afternoon.
|
|
59767
|
+
* @enum {string}
|
|
59768
|
+
*/
|
|
59769
|
+
outcome: "accepted" | "declined" | "thinking" | "no_answer";
|
|
59770
|
+
};
|
|
59771
|
+
};
|
|
59772
|
+
};
|
|
59773
|
+
responses: {
|
|
59774
|
+
/** @description The updated row, or null when it left the list */
|
|
59775
|
+
200: {
|
|
59776
|
+
headers: {
|
|
59777
|
+
[name: string]: unknown;
|
|
59778
|
+
};
|
|
59779
|
+
content: {
|
|
59780
|
+
/**
|
|
59781
|
+
* @example {
|
|
59782
|
+
* "data": {
|
|
59783
|
+
* "id": "7b7b7b7b-0000-4000-8000-000000000001",
|
|
59784
|
+
* "lineage_id": "7c7c7c7c-0000-4000-8000-000000000001",
|
|
59785
|
+
* "source": "native",
|
|
59786
|
+
* "budget_id": "7d7d7d7d-0000-4000-8000-000000000001",
|
|
59787
|
+
* "mirror_plan_id": null,
|
|
59788
|
+
* "vendor": null,
|
|
59789
|
+
* "budget_display_id": "P-0412",
|
|
59790
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
59791
|
+
* "phone": "+56960000001",
|
|
59792
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
59793
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
59794
|
+
* "conversation_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
59795
|
+
* "linea": {
|
|
59796
|
+
* "id": "d1d1d1d1-0000-4000-8000-000000000001",
|
|
59797
|
+
* "nombre": "Implantes"
|
|
59798
|
+
* },
|
|
59799
|
+
* "origin": {
|
|
59800
|
+
* "kind": "organic",
|
|
59801
|
+
* "label": "Orgánico",
|
|
59802
|
+
* "ad_id": null,
|
|
59803
|
+
* "ad_name": null,
|
|
59804
|
+
* "ad_set_name": null,
|
|
59805
|
+
* "campaign_name": null,
|
|
59806
|
+
* "first_touch_at": null,
|
|
59807
|
+
* "via": null
|
|
59808
|
+
* },
|
|
59809
|
+
* "professional_name": "Dra. Ana Soto",
|
|
59810
|
+
* "items": [
|
|
59811
|
+
* "Implante unitario"
|
|
59812
|
+
* ],
|
|
59813
|
+
* "item_count": 1,
|
|
59814
|
+
* "total_clp": 890000,
|
|
59815
|
+
* "issued_on": "2026-10-08",
|
|
59816
|
+
* "issued_label": "jueves 8 de octubre",
|
|
59817
|
+
* "days_since_issue": 1,
|
|
59818
|
+
* "step": 1,
|
|
59819
|
+
* "status": "active",
|
|
59820
|
+
* "stop_reason": null,
|
|
59821
|
+
* "touches_sent": 0,
|
|
59822
|
+
* "promised": false,
|
|
59823
|
+
* "outcome": {
|
|
59824
|
+
* "value": "thinking",
|
|
59825
|
+
* "at": "2026-10-09T14:12:03.000Z"
|
|
59826
|
+
* },
|
|
59827
|
+
* "touch": null
|
|
59828
|
+
* }
|
|
59829
|
+
* }
|
|
59830
|
+
*/
|
|
59831
|
+
"application/json": {
|
|
59832
|
+
data: {
|
|
59833
|
+
/** Format: uuid */
|
|
59834
|
+
id: string;
|
|
59835
|
+
/** Format: uuid */
|
|
59836
|
+
lineage_id: string;
|
|
59837
|
+
/**
|
|
59838
|
+
* @description `native`: a Vitrina presupuesto. `mirror`: a Dentalink / Medilink plan copied by the espejo de ingresos — it is accepted in the vendor, so there is no Vitrina accept link.
|
|
59839
|
+
* @enum {string}
|
|
59840
|
+
*/
|
|
59841
|
+
source: "native" | "mirror";
|
|
59842
|
+
/**
|
|
59843
|
+
* Format: uuid
|
|
59844
|
+
* @description Native rows only; null on a mirror row.
|
|
59845
|
+
*/
|
|
59846
|
+
budget_id: string | null;
|
|
59847
|
+
/**
|
|
59848
|
+
* Format: uuid
|
|
59849
|
+
* @description Mirror rows only: the `clinic_mirror_plan` the row follows.
|
|
59850
|
+
*/
|
|
59851
|
+
mirror_plan_id: string | null;
|
|
59852
|
+
/**
|
|
59853
|
+
* @description Mirror rows only: where the plan lives («Plan en Dentalink»).
|
|
59854
|
+
* @enum {string|null}
|
|
59855
|
+
*/
|
|
59856
|
+
vendor: "dentalink" | "medilink" | null;
|
|
59857
|
+
/** @description The folio, or the vendor plan number on a mirror row. */
|
|
59858
|
+
budget_display_id: string | null;
|
|
59859
|
+
patient_name: string | null;
|
|
59860
|
+
phone: string | null;
|
|
59861
|
+
/** Format: uuid */
|
|
59862
|
+
contact_id: string | null;
|
|
59863
|
+
/** Format: uuid */
|
|
59864
|
+
clinic_patient_id: string | null;
|
|
59865
|
+
/** Format: uuid */
|
|
59866
|
+
conversation_id: string | null;
|
|
59867
|
+
/** @description The patient's Línea (#4008): its open lead's, else its latest. */
|
|
59868
|
+
linea: {
|
|
59869
|
+
/** Format: uuid */
|
|
59870
|
+
id: string;
|
|
59871
|
+
nombre: string;
|
|
59872
|
+
} | null;
|
|
59873
|
+
/** @description The patient's Origen (null only if the read failed). */
|
|
59874
|
+
origin: {
|
|
59875
|
+
/**
|
|
59876
|
+
* @description `meta`: came from a Meta ad. `organic`: a linked contact with no ad touch. `unknown` («Sin dato»): no contact is linked to the person, so no ad touch can be read.
|
|
59877
|
+
* @enum {string}
|
|
59878
|
+
*/
|
|
59879
|
+
kind: "meta" | "organic" | "unknown";
|
|
59880
|
+
/** @description «Meta · Implantes octubre», «Meta» (ad name unknown), «Orgánico». */
|
|
59881
|
+
label: string;
|
|
59882
|
+
/** @description Meta only: the platform ad id (what `origin_ad_id` takes). */
|
|
59883
|
+
ad_id: string | null;
|
|
59884
|
+
ad_name: string | null;
|
|
59885
|
+
ad_set_name: string | null;
|
|
59886
|
+
campaign_name: string | null;
|
|
59887
|
+
/** @description Meta only: when they first wrote through the ad (or came back). */
|
|
59888
|
+
first_touch_at: string | null;
|
|
59889
|
+
/**
|
|
59890
|
+
* @description `first_message`: the first thing they wrote came from the ad. `returned`: they were already writing and came back through one. Both count as people from ads.
|
|
59891
|
+
* @enum {string|null}
|
|
59892
|
+
*/
|
|
59893
|
+
via: "first_message" | "returned" | null;
|
|
59894
|
+
} | null;
|
|
59895
|
+
professional_name: string | null;
|
|
59896
|
+
/** @description The first three item labels. */
|
|
59897
|
+
items: string[];
|
|
59898
|
+
item_count: number;
|
|
59899
|
+
/** @description `null` (and `items` empty) for a caller without `clinic_money:read`. */
|
|
59900
|
+
total_clp: number | null;
|
|
59901
|
+
issued_on: string;
|
|
59902
|
+
/** @description «lunes 21 de septiembre» */
|
|
59903
|
+
issued_label: string;
|
|
59904
|
+
days_since_issue: number;
|
|
59905
|
+
/** @description The step that falls today: 1 = día siguiente, 2 = día 7, 3 = día 21. */
|
|
59906
|
+
step: 1 | 2 | 3 | null;
|
|
59907
|
+
/** @enum {string} */
|
|
59908
|
+
status: "active" | "stopped";
|
|
59909
|
+
/** @enum {string|null} */
|
|
59910
|
+
stop_reason: "accepted" | "rejected" | "voided" | "expired" | "cita_booked" | "call_accepted" | "call_declined" | "replied" | "opted_out" | "no_marketing_consent" | "ladder_done" | "plan_paid" | null;
|
|
59911
|
+
touches_sent: number;
|
|
59912
|
+
promised: boolean;
|
|
59913
|
+
outcome: {
|
|
59914
|
+
/** @enum {string} */
|
|
59915
|
+
value: "accepted" | "declined" | "thinking" | "no_answer";
|
|
59916
|
+
at: string;
|
|
59917
|
+
} | null;
|
|
59918
|
+
touch: {
|
|
59919
|
+
/** @enum {string} */
|
|
59920
|
+
state: "awaiting_approval" | "scheduled" | "sent" | "skipped" | "refused" | "expired" | "failed";
|
|
59921
|
+
/** Format: uuid */
|
|
59922
|
+
action_id: string | null;
|
|
59923
|
+
message: string | null;
|
|
59924
|
+
reason: string | null;
|
|
59925
|
+
} | null;
|
|
59926
|
+
} | null;
|
|
59927
|
+
};
|
|
59928
|
+
};
|
|
59929
|
+
};
|
|
59930
|
+
/** @description Validation error */
|
|
59931
|
+
400: {
|
|
59932
|
+
headers: {
|
|
59933
|
+
[name: string]: unknown;
|
|
59934
|
+
};
|
|
59935
|
+
content: {
|
|
59936
|
+
"application/json": components["schemas"]["Error"];
|
|
59937
|
+
};
|
|
59938
|
+
};
|
|
59939
|
+
/** @description Unauthorized */
|
|
59940
|
+
401: {
|
|
59941
|
+
headers: {
|
|
59942
|
+
[name: string]: unknown;
|
|
59943
|
+
};
|
|
59944
|
+
content: {
|
|
59945
|
+
"application/json": components["schemas"]["Error"];
|
|
59946
|
+
};
|
|
59947
|
+
};
|
|
59948
|
+
/** @description Forbidden */
|
|
59949
|
+
403: {
|
|
59950
|
+
headers: {
|
|
59951
|
+
[name: string]: unknown;
|
|
59952
|
+
};
|
|
59953
|
+
content: {
|
|
59954
|
+
"application/json": components["schemas"]["Error"];
|
|
59955
|
+
};
|
|
59956
|
+
};
|
|
59957
|
+
/** @description Not found */
|
|
59958
|
+
404: {
|
|
59959
|
+
headers: {
|
|
59960
|
+
[name: string]: unknown;
|
|
59961
|
+
};
|
|
59962
|
+
content: {
|
|
59963
|
+
"application/json": components["schemas"]["Error"];
|
|
59964
|
+
};
|
|
59965
|
+
};
|
|
59966
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
59967
|
+
409: {
|
|
59968
|
+
headers: {
|
|
59969
|
+
[name: string]: unknown;
|
|
59970
|
+
};
|
|
59971
|
+
content: {
|
|
59972
|
+
"application/json": components["schemas"]["Error"];
|
|
59973
|
+
};
|
|
59974
|
+
};
|
|
59975
|
+
/** @description Rate limited */
|
|
59976
|
+
429: {
|
|
59977
|
+
headers: {
|
|
59978
|
+
[name: string]: unknown;
|
|
59979
|
+
};
|
|
59980
|
+
content: {
|
|
59981
|
+
"application/json": components["schemas"]["Error"];
|
|
59982
|
+
};
|
|
59983
|
+
};
|
|
59984
|
+
};
|
|
59985
|
+
};
|
|
59986
|
+
delete?: never;
|
|
59987
|
+
options?: never;
|
|
59988
|
+
head?: never;
|
|
59989
|
+
patch?: never;
|
|
59990
|
+
trace?: never;
|
|
59991
|
+
};
|
|
59992
|
+
"/clinic/budget-followups/sin-hora": {
|
|
59993
|
+
parameters: {
|
|
59994
|
+
query?: never;
|
|
59995
|
+
header?: never;
|
|
59996
|
+
path?: never;
|
|
59997
|
+
cookie?: never;
|
|
59998
|
+
};
|
|
59999
|
+
/**
|
|
60000
|
+
* «Llamar hoy» · «Sin hora»: open leads without a cita
|
|
60001
|
+
* @description Every OPEN lead whose contact has no cita that counts, however old (no age cut-off: dental and aesthetic demand is sporadic). A cita counts when it is confirmed or attended, or a hold still running; a cancelled or missed cita, past or future, does not — the lead is still waiting for a time. A lead leaves the list the moment a cita is booked. Sorted by call priority first (`priority` P1 to P4: P1 picked or asked for a time and was not booked, P2 wrote last and the clinic owes the reply, P3 interested, P4 cold), then lead `score` (highest first, unscored last), then the oldest last message first. Paged: `limit` (default 50, max 100) and `cursor` = the previous `next_cursor`; the cursor is a position, not an offset, so a lead leaving mid-scroll never skips another. `counts` covers the whole section, not the page: `total`, `logged` (an outcome tapped today) and `unlogged`. Each row carries what reception reads before dialling (`patient_name`, `phone`, `score`, `score_reason`, `last_message_at`) and today's `outcome`. `line` is the lead's Línea; `origin` is the lead's Origen (Meta with the ad, or Orgánico: the attribution Vitrina Ads reports). Narrow the section with `origin=meta|organic|unknown`, `origin_ad_id` and `linea_id` (a Línea id, or `none` for leads without one); `counts` follow the narrowing. Requires `clinic:read` and, for an API key or app, `clinic_patients:read`.
|
|
60002
|
+
*
|
|
60003
|
+
* **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`.
|
|
60004
|
+
*/
|
|
60005
|
+
get: {
|
|
60006
|
+
parameters: {
|
|
60007
|
+
query?: {
|
|
60008
|
+
/** @description Rows per page (default 50, max 100). */
|
|
60009
|
+
limit?: number;
|
|
60010
|
+
/** @description `next_cursor` of the previous page. */
|
|
60011
|
+
cursor?: string;
|
|
60012
|
+
/** @description Origen of the patient: `meta` (came from a Meta ad), `organic` (a linked contact with no ad touch) or `unknown` («Sin dato»: no linked contact). Same attribution as Vitrina Ads' people from ads. */
|
|
60013
|
+
origin?: "meta" | "organic" | "unknown";
|
|
60014
|
+
/** @description Narrow `origin=meta` to one Meta ad (its platform ad id). */
|
|
60015
|
+
origin_ad_id?: string;
|
|
60016
|
+
/** @description Narrow to one Línea: a clinic línea id, or `none` for leads without one. `counts` follow the narrowing. */
|
|
60017
|
+
linea_id?: string | "none";
|
|
60018
|
+
};
|
|
60019
|
+
header?: never;
|
|
60020
|
+
path?: never;
|
|
60021
|
+
cookie?: never;
|
|
60022
|
+
};
|
|
60023
|
+
requestBody?: never;
|
|
60024
|
+
responses: {
|
|
60025
|
+
/** @description One page of the Sin hora list */
|
|
60026
|
+
200: {
|
|
60027
|
+
headers: {
|
|
60028
|
+
[name: string]: unknown;
|
|
60029
|
+
};
|
|
60030
|
+
content: {
|
|
60031
|
+
/**
|
|
60032
|
+
* @example {
|
|
60033
|
+
* "data": {
|
|
60034
|
+
* "today": "2026-10-09",
|
|
60035
|
+
* "call_list": true,
|
|
60036
|
+
* "day_ends_at": "2026-10-09T22:00:00.000Z",
|
|
60037
|
+
* "counts": {
|
|
60038
|
+
* "total": 10,
|
|
60039
|
+
* "logged": 0,
|
|
60040
|
+
* "unlogged": 10,
|
|
60041
|
+
* "by_priority": {
|
|
60042
|
+
* "P1": 1,
|
|
60043
|
+
* "P2": 2,
|
|
60044
|
+
* "P3": 3,
|
|
60045
|
+
* "P4": 4
|
|
60046
|
+
* }
|
|
60047
|
+
* },
|
|
60048
|
+
* "rows": [
|
|
60049
|
+
* {
|
|
60050
|
+
* "priority": "P2",
|
|
60051
|
+
* "priority_fact": "wrote_last",
|
|
60052
|
+
* "priority_reason": "Escribió hace 3 h, le debemos respuesta",
|
|
60053
|
+
* "id": "5e5e5e5e-0000-4000-8000-000000000001",
|
|
60054
|
+
* "display_id": "L-89",
|
|
60055
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
60056
|
+
* "conversation_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
60057
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
60058
|
+
* "phone": "+56960000001",
|
|
60059
|
+
* "score": 72,
|
|
60060
|
+
* "score_reason": "Pidió precio de implantes y preguntó por horarios.",
|
|
60061
|
+
* "temperature": "warm",
|
|
60062
|
+
* "stage_name": "Nuevo",
|
|
60063
|
+
* "line": "Implantes",
|
|
60064
|
+
* "linea": {
|
|
60065
|
+
* "id": "d1d1d1d1-0000-4000-8000-000000000001",
|
|
60066
|
+
* "nombre": "Implantes",
|
|
60067
|
+
* "source": "keyword"
|
|
60068
|
+
* },
|
|
60069
|
+
* "origin": {
|
|
60070
|
+
* "kind": "organic",
|
|
60071
|
+
* "label": "Orgánico",
|
|
60072
|
+
* "ad_id": null,
|
|
60073
|
+
* "ad_name": null,
|
|
60074
|
+
* "ad_set_name": null,
|
|
60075
|
+
* "campaign_name": null,
|
|
60076
|
+
* "first_touch_at": null,
|
|
60077
|
+
* "via": null
|
|
60078
|
+
* },
|
|
60079
|
+
* "lead_created_at": "2026-09-20T15:02:11.000Z",
|
|
60080
|
+
* "last_message_at": "2026-10-09T13:40:00.000Z",
|
|
60081
|
+
* "days_since_last_message": 0,
|
|
60082
|
+
* "outcome": null,
|
|
60083
|
+
* "recontacto": null
|
|
60084
|
+
* }
|
|
60085
|
+
* ],
|
|
60086
|
+
* "next_cursor": null,
|
|
60087
|
+
* "viewer": {
|
|
60088
|
+
* "may_log": true,
|
|
60089
|
+
* "may_approve": true
|
|
60090
|
+
* }
|
|
60091
|
+
* }
|
|
60092
|
+
* }
|
|
60093
|
+
*/
|
|
60094
|
+
"application/json": {
|
|
60095
|
+
data: {
|
|
60096
|
+
today: string;
|
|
60097
|
+
call_list: boolean;
|
|
60098
|
+
/** @description When the clinic's day ends today (its latest closing among today's Horarios, clinic clock): if no call outcome is logged by then, the held WhatsApp is proposed for approval. `null` on a day the clinic does not open. */
|
|
60099
|
+
day_ends_at: string | null;
|
|
60100
|
+
counts: {
|
|
60101
|
+
/** @description Leads in the section. */
|
|
60102
|
+
total: number;
|
|
60103
|
+
/** @description Of those, with an outcome logged today. */
|
|
60104
|
+
logged: number;
|
|
60105
|
+
/** @description «n sin registrar» */
|
|
60106
|
+
unlogged: number;
|
|
60107
|
+
/** @description Leads per Prioridad de llamada, whole section. */
|
|
60108
|
+
by_priority: {
|
|
60109
|
+
P1: number;
|
|
60110
|
+
P2: number;
|
|
60111
|
+
P3: number;
|
|
60112
|
+
P4: number;
|
|
60113
|
+
};
|
|
60114
|
+
};
|
|
60115
|
+
rows: {
|
|
60116
|
+
/**
|
|
60117
|
+
* @description Prioridad de llamada, from conversation facts (no model): P1 picked or asked for a time and was not booked; P2 wrote last, the clinic owes the reply; P3 interested (score > 25); P4 cold (score <= 25).
|
|
60118
|
+
* @enum {string}
|
|
60119
|
+
*/
|
|
60120
|
+
priority: "P1" | "P2" | "P3" | "P4";
|
|
60121
|
+
/**
|
|
60122
|
+
* @description The fact that decided the tier.
|
|
60123
|
+
* @enum {string}
|
|
60124
|
+
*/
|
|
60125
|
+
priority_fact: "picked_time" | "asked_time" | "wrote_last" | "offered_unanswered" | "interested" | "cold";
|
|
60126
|
+
/** @description That fact as a Spanish sentence, e.g. «Escribió hace 3 h, le debemos respuesta». */
|
|
60127
|
+
priority_reason: string;
|
|
60128
|
+
/**
|
|
60129
|
+
* Format: uuid
|
|
60130
|
+
* @description The lead's id.
|
|
60131
|
+
*/
|
|
60132
|
+
id: string;
|
|
60133
|
+
/** @description «L-89». */
|
|
60134
|
+
display_id: string;
|
|
60135
|
+
/** Format: uuid */
|
|
60136
|
+
contact_id: string;
|
|
60137
|
+
/** Format: uuid */
|
|
60138
|
+
conversation_id: string | null;
|
|
60139
|
+
patient_name: string | null;
|
|
60140
|
+
phone: string | null;
|
|
60141
|
+
/** @description Lead score 0–100, highest first; `null` = never scored. */
|
|
60142
|
+
score: number | null;
|
|
60143
|
+
/** @description Why it scored what it did — the line read before dialling. */
|
|
60144
|
+
score_reason: string | null;
|
|
60145
|
+
temperature: string | null;
|
|
60146
|
+
stage_name: string | null;
|
|
60147
|
+
/** @description Nombre of the lead's Línea; `null` when it has none. */
|
|
60148
|
+
line: string | null;
|
|
60149
|
+
/** @description The lead's Línea as an object (id, nombre, and why it carries it); `null` when it has none. */
|
|
60150
|
+
linea: {
|
|
60151
|
+
/** Format: uuid */
|
|
60152
|
+
id: string;
|
|
60153
|
+
nombre: string;
|
|
60154
|
+
source: string | null;
|
|
60155
|
+
} | null;
|
|
60156
|
+
/** @description Origen of the lead (null only if the read failed). */
|
|
60157
|
+
origin: {
|
|
60158
|
+
/**
|
|
60159
|
+
* @description `meta`: came from a Meta ad. `organic`: a linked contact with no ad touch. `unknown` («Sin dato»): no contact is linked to the person, so no ad touch can be read.
|
|
60160
|
+
* @enum {string}
|
|
60161
|
+
*/
|
|
60162
|
+
kind: "meta" | "organic" | "unknown";
|
|
60163
|
+
/** @description «Meta · Implantes octubre», «Meta» (ad name unknown), «Orgánico». */
|
|
60164
|
+
label: string;
|
|
60165
|
+
/** @description Meta only: the platform ad id (what `origin_ad_id` takes). */
|
|
60166
|
+
ad_id: string | null;
|
|
60167
|
+
ad_name: string | null;
|
|
60168
|
+
ad_set_name: string | null;
|
|
60169
|
+
campaign_name: string | null;
|
|
60170
|
+
/** @description Meta only: when they first wrote through the ad (or came back). */
|
|
60171
|
+
first_touch_at: string | null;
|
|
60172
|
+
/**
|
|
60173
|
+
* @description `first_message`: the first thing they wrote came from the ad. `returned`: they were already writing and came back through one. Both count as people from ads.
|
|
60174
|
+
* @enum {string|null}
|
|
60175
|
+
*/
|
|
60176
|
+
via: "first_message" | "returned" | null;
|
|
60177
|
+
} | null;
|
|
60178
|
+
lead_created_at: string;
|
|
60179
|
+
last_message_at: string | null;
|
|
60180
|
+
days_since_last_message: number | null;
|
|
60181
|
+
/** @description Today's newest logged outcome. */
|
|
60182
|
+
outcome: {
|
|
60183
|
+
/** @enum {string} */
|
|
60184
|
+
value: "accepted" | "declined" | "thinking" | "no_answer";
|
|
60185
|
+
at: string;
|
|
60186
|
+
} | null;
|
|
60187
|
+
/** @description Where this patient's Recontacto stands today. `held`: the call goes first, no WhatsApp until the clinic's day ends. `proposed`: nobody logged a call, the WhatsApp waits for a person's approval. `null`: nothing pending. */
|
|
60188
|
+
recontacto: {
|
|
60189
|
+
/** @enum {string} */
|
|
60190
|
+
state: "held";
|
|
60191
|
+
} | {
|
|
60192
|
+
/** @enum {string} */
|
|
60193
|
+
state: "proposed";
|
|
60194
|
+
/**
|
|
60195
|
+
* Format: uuid
|
|
60196
|
+
* @description The outbound action waiting for approval: approve or discard it through the approvals (`/outbound/approvals`), like the inbox.
|
|
60197
|
+
*/
|
|
60198
|
+
action_id: string;
|
|
60199
|
+
/** Format: uuid */
|
|
60200
|
+
attempt_id: string;
|
|
60201
|
+
/** @description The drafted WhatsApp. */
|
|
60202
|
+
message: string | null;
|
|
60203
|
+
/** @description Why it is proposed. */
|
|
60204
|
+
reason: string | null;
|
|
60205
|
+
proposed_at: string;
|
|
60206
|
+
} | null;
|
|
60207
|
+
}[];
|
|
60208
|
+
next_cursor: string | null;
|
|
60209
|
+
viewer: {
|
|
60210
|
+
may_log: boolean;
|
|
60211
|
+
/** @description Whether the caller may approve or discard a proposed WhatsApp (`recontacto.state = proposed`) through the approvals. */
|
|
60212
|
+
may_approve: boolean;
|
|
60213
|
+
};
|
|
60214
|
+
};
|
|
60215
|
+
};
|
|
60216
|
+
};
|
|
60217
|
+
};
|
|
60218
|
+
/** @description Validation error */
|
|
60219
|
+
400: {
|
|
60220
|
+
headers: {
|
|
60221
|
+
[name: string]: unknown;
|
|
60222
|
+
};
|
|
60223
|
+
content: {
|
|
60224
|
+
"application/json": components["schemas"]["Error"];
|
|
60225
|
+
};
|
|
60226
|
+
};
|
|
60227
|
+
/** @description Unauthorized */
|
|
60228
|
+
401: {
|
|
60229
|
+
headers: {
|
|
60230
|
+
[name: string]: unknown;
|
|
60231
|
+
};
|
|
60232
|
+
content: {
|
|
60233
|
+
"application/json": components["schemas"]["Error"];
|
|
60234
|
+
};
|
|
60235
|
+
};
|
|
60236
|
+
/** @description Forbidden */
|
|
60237
|
+
403: {
|
|
60238
|
+
headers: {
|
|
60239
|
+
[name: string]: unknown;
|
|
60240
|
+
};
|
|
60241
|
+
content: {
|
|
60242
|
+
"application/json": components["schemas"]["Error"];
|
|
60243
|
+
};
|
|
60244
|
+
};
|
|
60245
|
+
/** @description Not found */
|
|
60246
|
+
404: {
|
|
60247
|
+
headers: {
|
|
60248
|
+
[name: string]: unknown;
|
|
60249
|
+
};
|
|
60250
|
+
content: {
|
|
60251
|
+
"application/json": components["schemas"]["Error"];
|
|
60252
|
+
};
|
|
60253
|
+
};
|
|
60254
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
60255
|
+
409: {
|
|
60256
|
+
headers: {
|
|
60257
|
+
[name: string]: unknown;
|
|
60258
|
+
};
|
|
60259
|
+
content: {
|
|
60260
|
+
"application/json": components["schemas"]["Error"];
|
|
60261
|
+
};
|
|
60262
|
+
};
|
|
60263
|
+
/** @description Rate limited */
|
|
60264
|
+
429: {
|
|
60265
|
+
headers: {
|
|
60266
|
+
[name: string]: unknown;
|
|
60267
|
+
};
|
|
60268
|
+
content: {
|
|
60269
|
+
"application/json": components["schemas"]["Error"];
|
|
60270
|
+
};
|
|
60271
|
+
};
|
|
60272
|
+
};
|
|
60273
|
+
};
|
|
60274
|
+
put?: never;
|
|
60275
|
+
post?: never;
|
|
60276
|
+
delete?: never;
|
|
60277
|
+
options?: never;
|
|
60278
|
+
head?: never;
|
|
60279
|
+
patch?: never;
|
|
60280
|
+
trace?: never;
|
|
60281
|
+
};
|
|
60282
|
+
"/clinic/budget-followups/sin-hora/{lead_id}/outcome": {
|
|
60283
|
+
parameters: {
|
|
60284
|
+
query?: never;
|
|
60285
|
+
header?: never;
|
|
60286
|
+
path?: never;
|
|
60287
|
+
cookie?: never;
|
|
60288
|
+
};
|
|
60289
|
+
get?: never;
|
|
60290
|
+
put?: never;
|
|
60291
|
+
/**
|
|
60292
|
+
* Log the outcome of a call to a Sin hora lead
|
|
60293
|
+
* @description The same four one-tap outcomes as the presupuesto rows (`accepted`, `declined`, `thinking`, `no_answer`), recorded on the lead's timeline as a `call_outcome` activity. A later tap the same clinic day supersedes the earlier (the timeline keeps both). It records the call and cancels the WhatsApp proposed for this patient, if any. `declined` («No quiere») also closes the lead as Perdido: it moves to its pipeline's lost stage with «No quiere» as the reason, leaves Sin hora and is never chased by Recontacto again; moving it back to a stage undoes it. Returns the updated row, or null when the lead left the section (a cita was booked, or «No quiere»). A pipeline with no lost stage refuses `declined`. 404 when the lead is not open. Requires `clinic:write`.
|
|
60294
|
+
*
|
|
60295
|
+
* **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`.
|
|
60296
|
+
*/
|
|
60297
|
+
post: {
|
|
60298
|
+
parameters: {
|
|
60299
|
+
query?: never;
|
|
60300
|
+
header?: {
|
|
60301
|
+
/** @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. */
|
|
60302
|
+
"Idempotency-Key"?: string;
|
|
60303
|
+
};
|
|
60304
|
+
path: {
|
|
60305
|
+
lead_id: string;
|
|
60306
|
+
};
|
|
60307
|
+
cookie?: never;
|
|
60308
|
+
};
|
|
60309
|
+
requestBody?: {
|
|
60310
|
+
content: {
|
|
60311
|
+
/**
|
|
60312
|
+
* @example {
|
|
60313
|
+
* "outcome": "no_answer"
|
|
60314
|
+
* }
|
|
60315
|
+
*/
|
|
60316
|
+
"application/json": {
|
|
60317
|
+
/**
|
|
60318
|
+
* @description `accepted` «Aceptó» and `declined` «No quiere» stop the follow-up; `thinking` «Lo va a pensar» skips today's WhatsApp; `no_answer` «No contestó» sends it this afternoon.
|
|
60319
|
+
* @enum {string}
|
|
60320
|
+
*/
|
|
60321
|
+
outcome: "accepted" | "declined" | "thinking" | "no_answer";
|
|
60322
|
+
};
|
|
60323
|
+
};
|
|
60324
|
+
};
|
|
60325
|
+
responses: {
|
|
60326
|
+
/** @description The updated row, or null when it left the list */
|
|
60327
|
+
200: {
|
|
60328
|
+
headers: {
|
|
60329
|
+
[name: string]: unknown;
|
|
60330
|
+
};
|
|
60331
|
+
content: {
|
|
60332
|
+
/**
|
|
60333
|
+
* @example {
|
|
60334
|
+
* "data": {
|
|
60335
|
+
* "priority": "P2",
|
|
60336
|
+
* "priority_fact": "wrote_last",
|
|
60337
|
+
* "priority_reason": "Escribió hace 3 h, le debemos respuesta",
|
|
60338
|
+
* "id": "5e5e5e5e-0000-4000-8000-000000000001",
|
|
60339
|
+
* "display_id": "L-89",
|
|
60340
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
60341
|
+
* "conversation_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
60342
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
60343
|
+
* "phone": "+56960000001",
|
|
60344
|
+
* "score": 72,
|
|
60345
|
+
* "score_reason": "Pidió precio de implantes y preguntó por horarios.",
|
|
60346
|
+
* "temperature": "warm",
|
|
60347
|
+
* "stage_name": "Nuevo",
|
|
60348
|
+
* "line": "Implantes",
|
|
60349
|
+
* "linea": {
|
|
60350
|
+
* "id": "d1d1d1d1-0000-4000-8000-000000000001",
|
|
60351
|
+
* "nombre": "Implantes",
|
|
60352
|
+
* "source": "keyword"
|
|
60353
|
+
* },
|
|
60354
|
+
* "origin": {
|
|
60355
|
+
* "kind": "organic",
|
|
60356
|
+
* "label": "Orgánico",
|
|
60357
|
+
* "ad_id": null,
|
|
60358
|
+
* "ad_name": null,
|
|
60359
|
+
* "ad_set_name": null,
|
|
60360
|
+
* "campaign_name": null,
|
|
60361
|
+
* "first_touch_at": null,
|
|
60362
|
+
* "via": null
|
|
60363
|
+
* },
|
|
60364
|
+
* "lead_created_at": "2026-09-20T15:02:11.000Z",
|
|
60365
|
+
* "last_message_at": "2026-10-09T13:40:00.000Z",
|
|
60366
|
+
* "days_since_last_message": 0,
|
|
60367
|
+
* "outcome": {
|
|
60368
|
+
* "value": "no_answer",
|
|
60369
|
+
* "at": "2026-10-09T14:12:03.000Z"
|
|
60370
|
+
* },
|
|
60371
|
+
* "recontacto": null
|
|
60372
|
+
* }
|
|
60373
|
+
* }
|
|
60374
|
+
*/
|
|
60375
|
+
"application/json": {
|
|
60376
|
+
data: {
|
|
60377
|
+
/**
|
|
60378
|
+
* @description Prioridad de llamada, from conversation facts (no model): P1 picked or asked for a time and was not booked; P2 wrote last, the clinic owes the reply; P3 interested (score > 25); P4 cold (score <= 25).
|
|
60379
|
+
* @enum {string}
|
|
60380
|
+
*/
|
|
60381
|
+
priority: "P1" | "P2" | "P3" | "P4";
|
|
60382
|
+
/**
|
|
60383
|
+
* @description The fact that decided the tier.
|
|
60384
|
+
* @enum {string}
|
|
60385
|
+
*/
|
|
60386
|
+
priority_fact: "picked_time" | "asked_time" | "wrote_last" | "offered_unanswered" | "interested" | "cold";
|
|
60387
|
+
/** @description That fact as a Spanish sentence, e.g. «Escribió hace 3 h, le debemos respuesta». */
|
|
60388
|
+
priority_reason: string;
|
|
60389
|
+
/**
|
|
60390
|
+
* Format: uuid
|
|
60391
|
+
* @description The lead's id.
|
|
60392
|
+
*/
|
|
60393
|
+
id: string;
|
|
60394
|
+
/** @description «L-89». */
|
|
60395
|
+
display_id: string;
|
|
60396
|
+
/** Format: uuid */
|
|
60397
|
+
contact_id: string;
|
|
60398
|
+
/** Format: uuid */
|
|
60399
|
+
conversation_id: string | null;
|
|
60400
|
+
patient_name: string | null;
|
|
60401
|
+
phone: string | null;
|
|
60402
|
+
/** @description Lead score 0–100, highest first; `null` = never scored. */
|
|
60403
|
+
score: number | null;
|
|
60404
|
+
/** @description Why it scored what it did — the line read before dialling. */
|
|
60405
|
+
score_reason: string | null;
|
|
60406
|
+
temperature: string | null;
|
|
60407
|
+
stage_name: string | null;
|
|
60408
|
+
/** @description Nombre of the lead's Línea; `null` when it has none. */
|
|
60409
|
+
line: string | null;
|
|
60410
|
+
/** @description The lead's Línea as an object (id, nombre, and why it carries it); `null` when it has none. */
|
|
60411
|
+
linea: {
|
|
60412
|
+
/** Format: uuid */
|
|
60413
|
+
id: string;
|
|
60414
|
+
nombre: string;
|
|
60415
|
+
source: string | null;
|
|
60416
|
+
} | null;
|
|
60417
|
+
/** @description Origen of the lead (null only if the read failed). */
|
|
60418
|
+
origin: {
|
|
60419
|
+
/**
|
|
60420
|
+
* @description `meta`: came from a Meta ad. `organic`: a linked contact with no ad touch. `unknown` («Sin dato»): no contact is linked to the person, so no ad touch can be read.
|
|
60421
|
+
* @enum {string}
|
|
60422
|
+
*/
|
|
60423
|
+
kind: "meta" | "organic" | "unknown";
|
|
60424
|
+
/** @description «Meta · Implantes octubre», «Meta» (ad name unknown), «Orgánico». */
|
|
60425
|
+
label: string;
|
|
60426
|
+
/** @description Meta only: the platform ad id (what `origin_ad_id` takes). */
|
|
60427
|
+
ad_id: string | null;
|
|
60428
|
+
ad_name: string | null;
|
|
60429
|
+
ad_set_name: string | null;
|
|
60430
|
+
campaign_name: string | null;
|
|
60431
|
+
/** @description Meta only: when they first wrote through the ad (or came back). */
|
|
60432
|
+
first_touch_at: string | null;
|
|
60433
|
+
/**
|
|
60434
|
+
* @description `first_message`: the first thing they wrote came from the ad. `returned`: they were already writing and came back through one. Both count as people from ads.
|
|
60435
|
+
* @enum {string|null}
|
|
60436
|
+
*/
|
|
60437
|
+
via: "first_message" | "returned" | null;
|
|
60438
|
+
} | null;
|
|
60439
|
+
lead_created_at: string;
|
|
60440
|
+
last_message_at: string | null;
|
|
60441
|
+
days_since_last_message: number | null;
|
|
60442
|
+
/** @description Today's newest logged outcome. */
|
|
60443
|
+
outcome: {
|
|
60444
|
+
/** @enum {string} */
|
|
60445
|
+
value: "accepted" | "declined" | "thinking" | "no_answer";
|
|
60446
|
+
at: string;
|
|
60447
|
+
} | null;
|
|
60448
|
+
/** @description Where this patient's Recontacto stands today. `held`: the call goes first, no WhatsApp until the clinic's day ends. `proposed`: nobody logged a call, the WhatsApp waits for a person's approval. `null`: nothing pending. */
|
|
60449
|
+
recontacto: {
|
|
60450
|
+
/** @enum {string} */
|
|
60451
|
+
state: "held";
|
|
60452
|
+
} | {
|
|
60453
|
+
/** @enum {string} */
|
|
60454
|
+
state: "proposed";
|
|
60455
|
+
/**
|
|
60456
|
+
* Format: uuid
|
|
60457
|
+
* @description The outbound action waiting for approval: approve or discard it through the approvals (`/outbound/approvals`), like the inbox.
|
|
60458
|
+
*/
|
|
60459
|
+
action_id: string;
|
|
60460
|
+
/** Format: uuid */
|
|
60461
|
+
attempt_id: string;
|
|
60462
|
+
/** @description The drafted WhatsApp. */
|
|
60463
|
+
message: string | null;
|
|
60464
|
+
/** @description Why it is proposed. */
|
|
60465
|
+
reason: string | null;
|
|
60466
|
+
proposed_at: string;
|
|
60467
|
+
} | null;
|
|
60468
|
+
} | null;
|
|
60469
|
+
};
|
|
60470
|
+
};
|
|
60471
|
+
};
|
|
60472
|
+
/** @description Validation error */
|
|
60473
|
+
400: {
|
|
60474
|
+
headers: {
|
|
60475
|
+
[name: string]: unknown;
|
|
60476
|
+
};
|
|
60477
|
+
content: {
|
|
60478
|
+
"application/json": components["schemas"]["Error"];
|
|
60479
|
+
};
|
|
60480
|
+
};
|
|
60481
|
+
/** @description Unauthorized */
|
|
60482
|
+
401: {
|
|
60483
|
+
headers: {
|
|
60484
|
+
[name: string]: unknown;
|
|
60485
|
+
};
|
|
60486
|
+
content: {
|
|
60487
|
+
"application/json": components["schemas"]["Error"];
|
|
60488
|
+
};
|
|
60489
|
+
};
|
|
60490
|
+
/** @description Forbidden */
|
|
60491
|
+
403: {
|
|
60492
|
+
headers: {
|
|
60493
|
+
[name: string]: unknown;
|
|
60494
|
+
};
|
|
60495
|
+
content: {
|
|
60496
|
+
"application/json": components["schemas"]["Error"];
|
|
60497
|
+
};
|
|
60498
|
+
};
|
|
60499
|
+
/** @description Not found */
|
|
60500
|
+
404: {
|
|
60501
|
+
headers: {
|
|
60502
|
+
[name: string]: unknown;
|
|
60503
|
+
};
|
|
60504
|
+
content: {
|
|
60505
|
+
"application/json": components["schemas"]["Error"];
|
|
60506
|
+
};
|
|
60507
|
+
};
|
|
60508
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
60509
|
+
409: {
|
|
60510
|
+
headers: {
|
|
60511
|
+
[name: string]: unknown;
|
|
60512
|
+
};
|
|
60513
|
+
content: {
|
|
60514
|
+
"application/json": components["schemas"]["Error"];
|
|
60515
|
+
};
|
|
60516
|
+
};
|
|
60517
|
+
/** @description Rate limited */
|
|
60518
|
+
429: {
|
|
60519
|
+
headers: {
|
|
60520
|
+
[name: string]: unknown;
|
|
60521
|
+
};
|
|
60522
|
+
content: {
|
|
60523
|
+
"application/json": components["schemas"]["Error"];
|
|
60524
|
+
};
|
|
60525
|
+
};
|
|
60526
|
+
};
|
|
60527
|
+
};
|
|
60528
|
+
delete?: never;
|
|
60529
|
+
options?: never;
|
|
60530
|
+
head?: never;
|
|
60531
|
+
patch?: never;
|
|
60532
|
+
trace?: never;
|
|
60533
|
+
};
|
|
59392
60534
|
"/clinic/lineas": {
|
|
59393
60535
|
parameters: {
|
|
59394
60536
|
query?: never;
|
|
@@ -85619,61 +86761,569 @@ interface paths {
|
|
|
85619
86761
|
patch?: never;
|
|
85620
86762
|
trace?: never;
|
|
85621
86763
|
};
|
|
85622
|
-
"/campaigns/{id}/test-send": {
|
|
86764
|
+
"/campaigns/{id}/test-send": {
|
|
86765
|
+
parameters: {
|
|
86766
|
+
query?: never;
|
|
86767
|
+
header?: never;
|
|
86768
|
+
path?: never;
|
|
86769
|
+
cookie?: never;
|
|
86770
|
+
};
|
|
86771
|
+
get?: never;
|
|
86772
|
+
put?: never;
|
|
86773
|
+
/**
|
|
86774
|
+
* Send a test of the campaign to up to five people
|
|
86775
|
+
* @description Sends the campaign, exactly as it will leave, to 1–5 recipients typed by hand — `phone` for a WhatsApp campaign, `email` for an email one — and answers one result per recipient: `sent` (with `provider_message_id`) or `failed` (with `error_code`). It writes NO recipient rows and does not touch the campaign’s status or counters, so it is safe on a scheduled, paused or sent campaign and leaves no trace in the stats; a `sending` or `cancelled` campaign answers 409 `campaign_not_testable`.
|
|
86776
|
+
*
|
|
86777
|
+
* **Readiness** is the real send’s, minus the audience: a WhatsApp test needs the template APPROVED on the campaign’s connected account and a resolvable media header (400 `header_media_missing` otherwise); an email test needs content and a verified sending domain.
|
|
86778
|
+
*
|
|
86779
|
+
* **Values.** Per template slot: `variables[slot]` when typed → else the campaign mapping read with the typed recipient as the contact (a `contact_field` slot gets the typed `name` / `phone` / `email`, else the mapping’s `fallback`; a `static` slot its text) → else the template’s example. A slot still empty refuses that recipient (`missing_variables`). The media header is always the campaign’s own (`template_params.header_media`) else the template default — never a test variable. Each result echoes `values` with the `source` of each.
|
|
86780
|
+
*
|
|
86781
|
+
* **WhatsApp tests are conversations.** The number’s contact and its active thread on the campaign’s account are found or created, and the message is stored there (`metadata.campaign_test: true`), so a reply reaches the AI agent with the campaign in context — and is never attributed to the campaign’s metrics. `conversation_id` points at it.
|
|
86782
|
+
*
|
|
86783
|
+
* **Refusals per recipient:** `invalid_phone`, `landline`, `invalid_email`, `duplicate`, `opted_out` (with `opt_out_reason`), `contact_blocked`, `safety_hold`, `missing_variables`, `email_not_verified` (SES sandbox: only verified addresses), `send_failed` (with `provider_code`).
|
|
86784
|
+
*
|
|
86785
|
+
* **Rate limit:** 20 test messages per campaign and 60 per workspace per hour, counted for the recipients actually sent to; past it the whole request is refused with 429 `RATE_LIMITED` (`details.retry_after_s`).
|
|
86786
|
+
*/
|
|
86787
|
+
post: {
|
|
86788
|
+
parameters: {
|
|
86789
|
+
query?: never;
|
|
86790
|
+
header?: {
|
|
86791
|
+
/** @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. */
|
|
86792
|
+
"Idempotency-Key"?: string;
|
|
86793
|
+
};
|
|
86794
|
+
path: {
|
|
86795
|
+
id: string;
|
|
86796
|
+
};
|
|
86797
|
+
cookie?: never;
|
|
86798
|
+
};
|
|
86799
|
+
requestBody?: {
|
|
86800
|
+
content: {
|
|
86801
|
+
/**
|
|
86802
|
+
* @example {
|
|
86803
|
+
* "recipients": [
|
|
86804
|
+
* {
|
|
86805
|
+
* "phone": "+56 9 1234 5678",
|
|
86806
|
+
* "name": "María González",
|
|
86807
|
+
* "variables": {
|
|
86808
|
+
* "1": "María"
|
|
86809
|
+
* }
|
|
86810
|
+
* }
|
|
86811
|
+
* ]
|
|
86812
|
+
* }
|
|
86813
|
+
*/
|
|
86814
|
+
"application/json": components["schemas"]["CampaignTestSendBody"];
|
|
86815
|
+
};
|
|
86816
|
+
};
|
|
86817
|
+
responses: {
|
|
86818
|
+
/** @description One result per recipient */
|
|
86819
|
+
200: {
|
|
86820
|
+
headers: {
|
|
86821
|
+
[name: string]: unknown;
|
|
86822
|
+
};
|
|
86823
|
+
content: {
|
|
86824
|
+
/**
|
|
86825
|
+
* @example {
|
|
86826
|
+
* "data": {
|
|
86827
|
+
* "campaign_id": "7a7a7a7a-0000-4000-8000-0000000000c1",
|
|
86828
|
+
* "channel": "whatsapp",
|
|
86829
|
+
* "header_media_url": null,
|
|
86830
|
+
* "remaining_this_hour": 4,
|
|
86831
|
+
* "results": [
|
|
86832
|
+
* {
|
|
86833
|
+
* "phone": "+56912345678",
|
|
86834
|
+
* "name": "María González",
|
|
86835
|
+
* "status": "sent",
|
|
86836
|
+
* "conversation_id": "7a7a7a7a-0000-4000-8000-000000000201",
|
|
86837
|
+
* "contact_id": "7a7a7a7a-0000-4000-8000-0000000000f1",
|
|
86838
|
+
* "rendered_text": "Hola María, tu próximo control es el 15 de noviembre.",
|
|
86839
|
+
* "values": {
|
|
86840
|
+
* "1": {
|
|
86841
|
+
* "value": "María",
|
|
86842
|
+
* "source": "variable"
|
|
86843
|
+
* },
|
|
86844
|
+
* "2": {
|
|
86845
|
+
* "value": "15 de noviembre",
|
|
86846
|
+
* "source": "static"
|
|
86847
|
+
* }
|
|
86848
|
+
* }
|
|
86849
|
+
* }
|
|
86850
|
+
* ]
|
|
86851
|
+
* }
|
|
86852
|
+
* }
|
|
86853
|
+
*/
|
|
86854
|
+
"application/json": {
|
|
86855
|
+
data: components["schemas"]["CampaignTestSendResult"];
|
|
86856
|
+
};
|
|
86857
|
+
};
|
|
86858
|
+
};
|
|
86859
|
+
/** @description Validation error */
|
|
86860
|
+
400: {
|
|
86861
|
+
headers: {
|
|
86862
|
+
[name: string]: unknown;
|
|
86863
|
+
};
|
|
86864
|
+
content: {
|
|
86865
|
+
"application/json": components["schemas"]["Error"];
|
|
86866
|
+
};
|
|
86867
|
+
};
|
|
86868
|
+
/** @description Unauthorized */
|
|
86869
|
+
401: {
|
|
86870
|
+
headers: {
|
|
86871
|
+
[name: string]: unknown;
|
|
86872
|
+
};
|
|
86873
|
+
content: {
|
|
86874
|
+
"application/json": components["schemas"]["Error"];
|
|
86875
|
+
};
|
|
86876
|
+
};
|
|
86877
|
+
/** @description Forbidden */
|
|
86878
|
+
403: {
|
|
86879
|
+
headers: {
|
|
86880
|
+
[name: string]: unknown;
|
|
86881
|
+
};
|
|
86882
|
+
content: {
|
|
86883
|
+
"application/json": components["schemas"]["Error"];
|
|
86884
|
+
};
|
|
86885
|
+
};
|
|
86886
|
+
/** @description Not found */
|
|
86887
|
+
404: {
|
|
86888
|
+
headers: {
|
|
86889
|
+
[name: string]: unknown;
|
|
86890
|
+
};
|
|
86891
|
+
content: {
|
|
86892
|
+
"application/json": components["schemas"]["Error"];
|
|
86893
|
+
};
|
|
86894
|
+
};
|
|
86895
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
86896
|
+
409: {
|
|
86897
|
+
headers: {
|
|
86898
|
+
[name: string]: unknown;
|
|
86899
|
+
};
|
|
86900
|
+
content: {
|
|
86901
|
+
"application/json": components["schemas"]["Error"];
|
|
86902
|
+
};
|
|
86903
|
+
};
|
|
86904
|
+
/** @description Rate limited */
|
|
86905
|
+
429: {
|
|
86906
|
+
headers: {
|
|
86907
|
+
[name: string]: unknown;
|
|
86908
|
+
};
|
|
86909
|
+
content: {
|
|
86910
|
+
"application/json": components["schemas"]["Error"];
|
|
86911
|
+
};
|
|
86912
|
+
};
|
|
86913
|
+
};
|
|
86914
|
+
};
|
|
86915
|
+
delete?: never;
|
|
86916
|
+
options?: never;
|
|
86917
|
+
head?: never;
|
|
86918
|
+
patch?: never;
|
|
86919
|
+
trace?: never;
|
|
86920
|
+
};
|
|
86921
|
+
"/clinic/agenda/feed": {
|
|
86922
|
+
parameters: {
|
|
86923
|
+
query?: never;
|
|
86924
|
+
header?: never;
|
|
86925
|
+
path?: never;
|
|
86926
|
+
cookie?: never;
|
|
86927
|
+
};
|
|
86928
|
+
/**
|
|
86929
|
+
* Agenda for a window, any engine, by professional and branch
|
|
86930
|
+
* @description Mirrored AND native appointments between `from` (inclusive) and `to` (EXCLUSIVE), bare `YYYY-MM-DD` days in the clinic's timezone; the window may not exceed 8 days. Cancelled citas are INCLUDED (the grid draws them muted). Unlike `GET /clinic/agenda`, `professional_id` and `location_id` are VITRINA uuids — `clinic_professional.id` and `location.id` — so one query serves a Medilink, a Reservo and a native clinic. Each row still carries the vendor's own ids under `vendor` for provenance: a row with `vendor.professional_id` set and `professional: null` is a roster gap, never a cita nobody is attending. Never calls the clinic API. `flags` are the clinical alerts the clinic shows on the block: clinical-record content, returned to an API key or personal token only when it also holds `clinic_record:read`. `booking_kind` is the cita's Tipo de agendamiento: `new` (Nuevo: it would be a primera visita and the patient never booked before), `new_rebooked` (Nuevo · reagenda: a primera visita, but the patient had earlier bookings and never came) or `in_treatment` (En tratamiento: every other cita); null on a row that is not a patient's cita. It uses the primera-visita rule Vitrina Ads counts, so a patient back after 12 months without an attended cita is `new`. `origin` is the patient's Origen (`kind` `meta` with the ad, ad set and campaign names, or `organic`) — the attribution Vitrina Ads reports, one definition; null on a row that is not a patient's cita. Filter with `origin=meta|organic|unknown` and, for Meta, `origin_ad_id` (a Meta ad id): rows that are not a patient's cita never match. `is_diagnosis` marks a diagnosis cita — a primera visita (`booking_kind` `new` / `new_rebooked`), an entry prestación the clinic confirmed, or a cita the clinic named as an evaluación / diagnóstico (the prestación, or the vendor's tratamiento label) unless its prestación is confirmed not to be an entry; `diagnosis=true` returns only those. `booked_via` says how the cita was booked: `agent` (Vitrina's AI agent, with the conversation `channel`), `online` (the patient on a booking page), `whatsapp` (a person booked it within 48 h of a WhatsApp exchange with the patient), `staff` (a team member in Vitrina, `by`), `vendor` (keyed straight into the clinic's system) or `calendar`; `booked_at` is the vendor's own creation time when known. `patient_paid` is what the patient paid on their plans, all time (espejo de ingresos abonos plus presupuesto allocations), returned only to a caller holding `clinic_money:read`.
|
|
86931
|
+
*
|
|
86932
|
+
* **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`.
|
|
86933
|
+
*/
|
|
86934
|
+
get: {
|
|
86935
|
+
parameters: {
|
|
86936
|
+
query: {
|
|
86937
|
+
from: string;
|
|
86938
|
+
to: string;
|
|
86939
|
+
professional_id?: string;
|
|
86940
|
+
location_id?: string;
|
|
86941
|
+
resource_id?: string;
|
|
86942
|
+
status?: ("pending_hold" | "confirmed" | "cancelled" | "completed" | "no_show")[];
|
|
86943
|
+
kind?: ("test_drive" | "external" | "block" | "clinic")[];
|
|
86944
|
+
/** @description Origen of the patient: `meta` (came from a Meta ad), `organic` (a linked contact with no ad touch) or `unknown` («Sin dato»: no linked contact). Same attribution as Vitrina Ads' people from ads. */
|
|
86945
|
+
origin?: "meta" | "organic" | "unknown";
|
|
86946
|
+
/** @description Narrow `origin=meta` to one Meta ad (its platform ad id). */
|
|
86947
|
+
origin_ad_id?: string;
|
|
86948
|
+
diagnosis?: "true" | "false";
|
|
86949
|
+
};
|
|
86950
|
+
header?: never;
|
|
86951
|
+
path?: never;
|
|
86952
|
+
cookie?: never;
|
|
86953
|
+
};
|
|
86954
|
+
requestBody?: never;
|
|
86955
|
+
responses: {
|
|
86956
|
+
/** @description Agenda feed */
|
|
86957
|
+
200: {
|
|
86958
|
+
headers: {
|
|
86959
|
+
[name: string]: unknown;
|
|
86960
|
+
};
|
|
86961
|
+
content: {
|
|
86962
|
+
/**
|
|
86963
|
+
* @example {
|
|
86964
|
+
* "data": [
|
|
86965
|
+
* {
|
|
86966
|
+
* "id": "eeeeeeee-0000-4000-8000-000000000001",
|
|
86967
|
+
* "display_id": "A-1",
|
|
86968
|
+
* "engine": "native",
|
|
86969
|
+
* "external_id": null,
|
|
86970
|
+
* "kind": "clinic",
|
|
86971
|
+
* "status": "confirmed",
|
|
86972
|
+
* "clinic_status_id": null,
|
|
86973
|
+
* "status_label": null,
|
|
86974
|
+
* "status_color": null,
|
|
86975
|
+
* "starts_at": "2026-09-23T13:30:00.000Z",
|
|
86976
|
+
* "ends_at": "2026-09-23T14:00:00.000Z",
|
|
86977
|
+
* "arrival_state": "scheduled",
|
|
86978
|
+
* "professional": {
|
|
86979
|
+
* "id": "ffffffff-0000-4000-8000-000000000001",
|
|
86980
|
+
* "name": "Ana"
|
|
86981
|
+
* },
|
|
86982
|
+
* "location": {
|
|
86983
|
+
* "id": "b1b1b1b1-0000-4000-8000-000000000002",
|
|
86984
|
+
* "name": "Sucursal Maipú"
|
|
86985
|
+
* },
|
|
86986
|
+
* "resource": null,
|
|
86987
|
+
* "service": null,
|
|
86988
|
+
* "patient": {
|
|
86989
|
+
* "id": "12121212-0000-4000-8000-000000000001",
|
|
86990
|
+
* "name": "María José Fuentes Lagos",
|
|
86991
|
+
* "external_id": null
|
|
86992
|
+
* },
|
|
86993
|
+
* "contact": {
|
|
86994
|
+
* "id": "22222222-0000-4000-8000-000000000001",
|
|
86995
|
+
* "name": "María José Fuentes Lagos"
|
|
86996
|
+
* },
|
|
86997
|
+
* "customer_name": "María José Fuentes Lagos",
|
|
86998
|
+
* "notes": "Avisar al +56987654321 si se atrasa",
|
|
86999
|
+
* "money": null,
|
|
87000
|
+
* "booking_kind": "new",
|
|
87001
|
+
* "is_diagnosis": true,
|
|
87002
|
+
* "booked_via": {
|
|
87003
|
+
* "kind": "agent",
|
|
87004
|
+
* "channel": "whatsapp",
|
|
87005
|
+
* "by": null,
|
|
87006
|
+
* "booked_at": "2026-09-21T18:04:00.000Z"
|
|
87007
|
+
* },
|
|
87008
|
+
* "patient_paid": 250000,
|
|
87009
|
+
* "flags": [
|
|
87010
|
+
* {
|
|
87011
|
+
* "id": "13131313-0000-4000-8000-000000000001",
|
|
87012
|
+
* "kind": "alergia",
|
|
87013
|
+
* "label": "Alergia a penicilina",
|
|
87014
|
+
* "severity": "severa"
|
|
87015
|
+
* }
|
|
87016
|
+
* ],
|
|
87017
|
+
* "vendor": {
|
|
87018
|
+
* "professional_id": null,
|
|
87019
|
+
* "professional_name": null,
|
|
87020
|
+
* "sucursal_id": null,
|
|
87021
|
+
* "agenda_id": null,
|
|
87022
|
+
* "sillon": null,
|
|
87023
|
+
* "status_code": null
|
|
87024
|
+
* }
|
|
87025
|
+
* }
|
|
87026
|
+
* ]
|
|
87027
|
+
* }
|
|
87028
|
+
*/
|
|
87029
|
+
"application/json": {
|
|
87030
|
+
data?: unknown;
|
|
87031
|
+
meta?: {
|
|
87032
|
+
[key: string]: unknown;
|
|
87033
|
+
};
|
|
87034
|
+
};
|
|
87035
|
+
};
|
|
87036
|
+
};
|
|
87037
|
+
/** @description Validation error */
|
|
87038
|
+
400: {
|
|
87039
|
+
headers: {
|
|
87040
|
+
[name: string]: unknown;
|
|
87041
|
+
};
|
|
87042
|
+
content: {
|
|
87043
|
+
"application/json": components["schemas"]["Error"];
|
|
87044
|
+
};
|
|
87045
|
+
};
|
|
87046
|
+
/** @description Unauthorized */
|
|
87047
|
+
401: {
|
|
87048
|
+
headers: {
|
|
87049
|
+
[name: string]: unknown;
|
|
87050
|
+
};
|
|
87051
|
+
content: {
|
|
87052
|
+
"application/json": components["schemas"]["Error"];
|
|
87053
|
+
};
|
|
87054
|
+
};
|
|
87055
|
+
/** @description Forbidden */
|
|
87056
|
+
403: {
|
|
87057
|
+
headers: {
|
|
87058
|
+
[name: string]: unknown;
|
|
87059
|
+
};
|
|
87060
|
+
content: {
|
|
87061
|
+
"application/json": components["schemas"]["Error"];
|
|
87062
|
+
};
|
|
87063
|
+
};
|
|
87064
|
+
/** @description Not found */
|
|
87065
|
+
404: {
|
|
87066
|
+
headers: {
|
|
87067
|
+
[name: string]: unknown;
|
|
87068
|
+
};
|
|
87069
|
+
content: {
|
|
87070
|
+
"application/json": components["schemas"]["Error"];
|
|
87071
|
+
};
|
|
87072
|
+
};
|
|
87073
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
87074
|
+
409: {
|
|
87075
|
+
headers: {
|
|
87076
|
+
[name: string]: unknown;
|
|
87077
|
+
};
|
|
87078
|
+
content: {
|
|
87079
|
+
"application/json": components["schemas"]["Error"];
|
|
87080
|
+
};
|
|
87081
|
+
};
|
|
87082
|
+
/** @description Rate limited */
|
|
87083
|
+
429: {
|
|
87084
|
+
headers: {
|
|
87085
|
+
[name: string]: unknown;
|
|
87086
|
+
};
|
|
87087
|
+
content: {
|
|
87088
|
+
"application/json": components["schemas"]["Error"];
|
|
87089
|
+
};
|
|
87090
|
+
};
|
|
87091
|
+
};
|
|
87092
|
+
};
|
|
87093
|
+
put?: never;
|
|
87094
|
+
post?: never;
|
|
87095
|
+
delete?: never;
|
|
87096
|
+
options?: never;
|
|
87097
|
+
head?: never;
|
|
87098
|
+
patch?: never;
|
|
87099
|
+
trace?: never;
|
|
87100
|
+
};
|
|
87101
|
+
"/clinic/agenda/diagnosticos": {
|
|
87102
|
+
parameters: {
|
|
87103
|
+
query?: never;
|
|
87104
|
+
header?: never;
|
|
87105
|
+
path?: never;
|
|
87106
|
+
cookie?: never;
|
|
87107
|
+
};
|
|
87108
|
+
/**
|
|
87109
|
+
* Diagnósticos: one day of diagnosis citas with plans and abono
|
|
87110
|
+
* @description The closing routine's worklist. `date` (`YYYY-MM-DD`, the clinic's clock; default today) returns that day's diagnosis citas in time order — the same `is_diagnosis` rule as `GET /clinic/agenda/feed` — each with its attendance (`attended`, `no_show`, `cancelled`, `booked`), professional, Tipo de agendamiento and Origen, and the patient's plans of the last 12 months: from the espejo de ingresos (the vendor's plan total and abonado) for a Dentalink clinic, from its presupuestos (total and what was allocated to them) for a native one; plans of $0 are not plans. At most 3 plans per patient are listed, `plans_count`, `plan_total` and `paid_total` cover all of them. `summary` counts the day (cancelled citas are counted apart and never as Meta) and `upcoming` the next 5 working days (a Sunday appears only when it holds a diagnosis cita). Plans are money: without `clinic_money:read` every `money` is null and `money_withheld` is true; `plan_created_on_day` stays. Never calls the clinic API.
|
|
87111
|
+
*
|
|
87112
|
+
* **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`.
|
|
87113
|
+
*/
|
|
87114
|
+
get: {
|
|
87115
|
+
parameters: {
|
|
87116
|
+
query?: {
|
|
87117
|
+
date?: string;
|
|
87118
|
+
location_id?: string;
|
|
87119
|
+
professional_id?: string;
|
|
87120
|
+
};
|
|
87121
|
+
header?: never;
|
|
87122
|
+
path?: never;
|
|
87123
|
+
cookie?: never;
|
|
87124
|
+
};
|
|
87125
|
+
requestBody?: never;
|
|
87126
|
+
responses: {
|
|
87127
|
+
/** @description Diagnosis day */
|
|
87128
|
+
200: {
|
|
87129
|
+
headers: {
|
|
87130
|
+
[name: string]: unknown;
|
|
87131
|
+
};
|
|
87132
|
+
content: {
|
|
87133
|
+
/**
|
|
87134
|
+
* @example {
|
|
87135
|
+
* "data": {
|
|
87136
|
+
* "date": "2026-09-23",
|
|
87137
|
+
* "summary": {
|
|
87138
|
+
* "total": 1,
|
|
87139
|
+
* "attended": 1,
|
|
87140
|
+
* "no_show": 0,
|
|
87141
|
+
* "cancelled": 0,
|
|
87142
|
+
* "meta": 0,
|
|
87143
|
+
* "plan_created_on_day": 1
|
|
87144
|
+
* },
|
|
87145
|
+
* "rows": [
|
|
87146
|
+
* {
|
|
87147
|
+
* "appointment_id": "eeeeeeee-0000-4000-8000-000000000001",
|
|
87148
|
+
* "display_id": "A-1",
|
|
87149
|
+
* "starts_at": "2026-09-23T13:30:00.000Z",
|
|
87150
|
+
* "ends_at": "2026-09-23T14:00:00.000Z",
|
|
87151
|
+
* "status": "completed",
|
|
87152
|
+
* "status_label": "Atendido",
|
|
87153
|
+
* "attendance": "attended",
|
|
87154
|
+
* "patient": {
|
|
87155
|
+
* "id": "12121212-0000-4000-8000-000000000001",
|
|
87156
|
+
* "name": "María José Fuentes Lagos",
|
|
87157
|
+
* "external_id": null
|
|
87158
|
+
* },
|
|
87159
|
+
* "professional": {
|
|
87160
|
+
* "id": "ffffffff-0000-4000-8000-000000000001",
|
|
87161
|
+
* "name": "Ana"
|
|
87162
|
+
* },
|
|
87163
|
+
* "service": null,
|
|
87164
|
+
* "location": {
|
|
87165
|
+
* "id": "b1b1b1b1-0000-4000-8000-000000000002",
|
|
87166
|
+
* "name": "Sucursal Maipú"
|
|
87167
|
+
* },
|
|
87168
|
+
* "booking_kind": "new",
|
|
87169
|
+
* "origin": {
|
|
87170
|
+
* "kind": "organic",
|
|
87171
|
+
* "label": "Orgánico",
|
|
87172
|
+
* "ad_id": null,
|
|
87173
|
+
* "ad_name": null,
|
|
87174
|
+
* "ad_set_name": null,
|
|
87175
|
+
* "campaign_name": null,
|
|
87176
|
+
* "first_touch_at": null,
|
|
87177
|
+
* "via": null
|
|
87178
|
+
* },
|
|
87179
|
+
* "external_id": null,
|
|
87180
|
+
* "engine": "native",
|
|
87181
|
+
* "money": {
|
|
87182
|
+
* "plans": [
|
|
87183
|
+
* {
|
|
87184
|
+
* "source": "native",
|
|
87185
|
+
* "id": "eeeeeeee-0000-4000-8000-000000000002",
|
|
87186
|
+
* "label": "E-12",
|
|
87187
|
+
* "day": "2026-09-23",
|
|
87188
|
+
* "total": 1250000,
|
|
87189
|
+
* "paid": 250000,
|
|
87190
|
+
* "status": "accepted",
|
|
87191
|
+
* "professional_name": "Ana Rojas",
|
|
87192
|
+
* "created_on_day": true
|
|
87193
|
+
* }
|
|
87194
|
+
* ],
|
|
87195
|
+
* "plans_count": 1,
|
|
87196
|
+
* "plan_total": 1250000,
|
|
87197
|
+
* "paid_total": 250000
|
|
87198
|
+
* },
|
|
87199
|
+
* "plan_created_on_day": true
|
|
87200
|
+
* }
|
|
87201
|
+
* ],
|
|
87202
|
+
* "upcoming": [
|
|
87203
|
+
* {
|
|
87204
|
+
* "date": "2026-09-24",
|
|
87205
|
+
* "count": 4
|
|
87206
|
+
* },
|
|
87207
|
+
* {
|
|
87208
|
+
* "date": "2026-09-25",
|
|
87209
|
+
* "count": 3
|
|
87210
|
+
* },
|
|
87211
|
+
* {
|
|
87212
|
+
* "date": "2026-09-26",
|
|
87213
|
+
* "count": 1
|
|
87214
|
+
* },
|
|
87215
|
+
* {
|
|
87216
|
+
* "date": "2026-09-28",
|
|
87217
|
+
* "count": 5
|
|
87218
|
+
* },
|
|
87219
|
+
* {
|
|
87220
|
+
* "date": "2026-09-29",
|
|
87221
|
+
* "count": 2
|
|
87222
|
+
* }
|
|
87223
|
+
* ],
|
|
87224
|
+
* "money_withheld": false
|
|
87225
|
+
* }
|
|
87226
|
+
* }
|
|
87227
|
+
*/
|
|
87228
|
+
"application/json": {
|
|
87229
|
+
data?: unknown;
|
|
87230
|
+
meta?: {
|
|
87231
|
+
[key: string]: unknown;
|
|
87232
|
+
};
|
|
87233
|
+
};
|
|
87234
|
+
};
|
|
87235
|
+
};
|
|
87236
|
+
/** @description Validation error */
|
|
87237
|
+
400: {
|
|
87238
|
+
headers: {
|
|
87239
|
+
[name: string]: unknown;
|
|
87240
|
+
};
|
|
87241
|
+
content: {
|
|
87242
|
+
"application/json": components["schemas"]["Error"];
|
|
87243
|
+
};
|
|
87244
|
+
};
|
|
87245
|
+
/** @description Unauthorized */
|
|
87246
|
+
401: {
|
|
87247
|
+
headers: {
|
|
87248
|
+
[name: string]: unknown;
|
|
87249
|
+
};
|
|
87250
|
+
content: {
|
|
87251
|
+
"application/json": components["schemas"]["Error"];
|
|
87252
|
+
};
|
|
87253
|
+
};
|
|
87254
|
+
/** @description Forbidden */
|
|
87255
|
+
403: {
|
|
87256
|
+
headers: {
|
|
87257
|
+
[name: string]: unknown;
|
|
87258
|
+
};
|
|
87259
|
+
content: {
|
|
87260
|
+
"application/json": components["schemas"]["Error"];
|
|
87261
|
+
};
|
|
87262
|
+
};
|
|
87263
|
+
/** @description Not found */
|
|
87264
|
+
404: {
|
|
87265
|
+
headers: {
|
|
87266
|
+
[name: string]: unknown;
|
|
87267
|
+
};
|
|
87268
|
+
content: {
|
|
87269
|
+
"application/json": components["schemas"]["Error"];
|
|
87270
|
+
};
|
|
87271
|
+
};
|
|
87272
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
87273
|
+
409: {
|
|
87274
|
+
headers: {
|
|
87275
|
+
[name: string]: unknown;
|
|
87276
|
+
};
|
|
87277
|
+
content: {
|
|
87278
|
+
"application/json": components["schemas"]["Error"];
|
|
87279
|
+
};
|
|
87280
|
+
};
|
|
87281
|
+
/** @description Rate limited */
|
|
87282
|
+
429: {
|
|
87283
|
+
headers: {
|
|
87284
|
+
[name: string]: unknown;
|
|
87285
|
+
};
|
|
87286
|
+
content: {
|
|
87287
|
+
"application/json": components["schemas"]["Error"];
|
|
87288
|
+
};
|
|
87289
|
+
};
|
|
87290
|
+
};
|
|
87291
|
+
};
|
|
87292
|
+
put?: never;
|
|
87293
|
+
post?: never;
|
|
87294
|
+
delete?: never;
|
|
87295
|
+
options?: never;
|
|
87296
|
+
head?: never;
|
|
87297
|
+
patch?: never;
|
|
87298
|
+
trace?: never;
|
|
87299
|
+
};
|
|
87300
|
+
"/clinic/agenda/month": {
|
|
85623
87301
|
parameters: {
|
|
85624
87302
|
query?: never;
|
|
85625
87303
|
header?: never;
|
|
85626
87304
|
path?: never;
|
|
85627
87305
|
cookie?: never;
|
|
85628
87306
|
};
|
|
85629
|
-
get?: never;
|
|
85630
|
-
put?: never;
|
|
85631
87307
|
/**
|
|
85632
|
-
*
|
|
85633
|
-
* @description
|
|
87308
|
+
* Agenda month: citas per day, by Origen
|
|
87309
|
+
* @description Counts per day of one `month` (`YYYY-MM`, the clinic's clock), read in one pass: `citas` (patients' citas that still stand), split by Origen (`meta`, `organic`, `unknown` — the same resolver as the feed and Vitrina Ads), `diagnosis` (diagnosis citas among them, the feed's `is_diagnosis` rule) and `cancelled` (anuladas, counted apart). Blocks and the workspace's own events never count. Optional `location_id` / `professional_id` (Vitrina uuids). Never calls the clinic API.
|
|
85634
87310
|
*
|
|
85635
|
-
* **
|
|
85636
|
-
*
|
|
85637
|
-
* **Values.** Per template slot: `variables[slot]` when typed → else the campaign mapping read with the typed recipient as the contact (a `contact_field` slot gets the typed `name` / `phone` / `email`, else the mapping’s `fallback`; a `static` slot its text) → else the template’s example. A slot still empty refuses that recipient (`missing_variables`). The media header is always the campaign’s own (`template_params.header_media`) else the template default — never a test variable. Each result echoes `values` with the `source` of each.
|
|
85638
|
-
*
|
|
85639
|
-
* **WhatsApp tests are conversations.** The number’s contact and its active thread on the campaign’s account are found or created, and the message is stored there (`metadata.campaign_test: true`), so a reply reaches the AI agent with the campaign in context — and is never attributed to the campaign’s metrics. `conversation_id` points at it.
|
|
85640
|
-
*
|
|
85641
|
-
* **Refusals per recipient:** `invalid_phone`, `landline`, `invalid_email`, `duplicate`, `opted_out` (with `opt_out_reason`), `contact_blocked`, `safety_hold`, `missing_variables`, `email_not_verified` (SES sandbox: only verified addresses), `send_failed` (with `provider_code`).
|
|
85642
|
-
*
|
|
85643
|
-
* **Rate limit:** 20 test messages per campaign and 60 per workspace per hour, counted for the recipients actually sent to; past it the whole request is refused with 429 `RATE_LIMITED` (`details.retry_after_s`).
|
|
87311
|
+
* **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`.
|
|
85644
87312
|
*/
|
|
85645
|
-
|
|
87313
|
+
get: {
|
|
85646
87314
|
parameters: {
|
|
85647
|
-
query
|
|
85648
|
-
|
|
85649
|
-
|
|
85650
|
-
|
|
85651
|
-
};
|
|
85652
|
-
path: {
|
|
85653
|
-
id: string;
|
|
87315
|
+
query: {
|
|
87316
|
+
month: string;
|
|
87317
|
+
location_id?: string;
|
|
87318
|
+
professional_id?: string;
|
|
85654
87319
|
};
|
|
87320
|
+
header?: never;
|
|
87321
|
+
path?: never;
|
|
85655
87322
|
cookie?: never;
|
|
85656
87323
|
};
|
|
85657
|
-
requestBody?:
|
|
85658
|
-
content: {
|
|
85659
|
-
/**
|
|
85660
|
-
* @example {
|
|
85661
|
-
* "recipients": [
|
|
85662
|
-
* {
|
|
85663
|
-
* "phone": "+56 9 1234 5678",
|
|
85664
|
-
* "name": "María González",
|
|
85665
|
-
* "variables": {
|
|
85666
|
-
* "1": "María"
|
|
85667
|
-
* }
|
|
85668
|
-
* }
|
|
85669
|
-
* ]
|
|
85670
|
-
* }
|
|
85671
|
-
*/
|
|
85672
|
-
"application/json": components["schemas"]["CampaignTestSendBody"];
|
|
85673
|
-
};
|
|
85674
|
-
};
|
|
87324
|
+
requestBody?: never;
|
|
85675
87325
|
responses: {
|
|
85676
|
-
/** @description
|
|
87326
|
+
/** @description Agenda month */
|
|
85677
87327
|
200: {
|
|
85678
87328
|
headers: {
|
|
85679
87329
|
[name: string]: unknown;
|
|
@@ -85682,35 +87332,35 @@ interface paths {
|
|
|
85682
87332
|
/**
|
|
85683
87333
|
* @example {
|
|
85684
87334
|
* "data": {
|
|
85685
|
-
* "
|
|
85686
|
-
* "
|
|
85687
|
-
* "header_media_url": null,
|
|
85688
|
-
* "remaining_this_hour": 4,
|
|
85689
|
-
* "results": [
|
|
87335
|
+
* "month": "2026-10",
|
|
87336
|
+
* "days": [
|
|
85690
87337
|
* {
|
|
85691
|
-
* "
|
|
85692
|
-
* "
|
|
85693
|
-
* "
|
|
85694
|
-
* "
|
|
85695
|
-
* "
|
|
85696
|
-
* "
|
|
85697
|
-
* "
|
|
85698
|
-
*
|
|
85699
|
-
*
|
|
85700
|
-
*
|
|
85701
|
-
*
|
|
85702
|
-
*
|
|
85703
|
-
*
|
|
85704
|
-
*
|
|
85705
|
-
*
|
|
85706
|
-
*
|
|
87338
|
+
* "date": "2026-10-01",
|
|
87339
|
+
* "citas": 42,
|
|
87340
|
+
* "meta": 9,
|
|
87341
|
+
* "organic": 20,
|
|
87342
|
+
* "unknown": 13,
|
|
87343
|
+
* "diagnosis": 7,
|
|
87344
|
+
* "cancelled": 4
|
|
87345
|
+
* },
|
|
87346
|
+
* {
|
|
87347
|
+
* "date": "2026-10-02",
|
|
87348
|
+
* "citas": 38,
|
|
87349
|
+
* "meta": 6,
|
|
87350
|
+
* "organic": 19,
|
|
87351
|
+
* "unknown": 13,
|
|
87352
|
+
* "diagnosis": 5,
|
|
87353
|
+
* "cancelled": 2
|
|
85707
87354
|
* }
|
|
85708
87355
|
* ]
|
|
85709
87356
|
* }
|
|
85710
87357
|
* }
|
|
85711
87358
|
*/
|
|
85712
87359
|
"application/json": {
|
|
85713
|
-
data
|
|
87360
|
+
data?: unknown;
|
|
87361
|
+
meta?: {
|
|
87362
|
+
[key: string]: unknown;
|
|
87363
|
+
};
|
|
85714
87364
|
};
|
|
85715
87365
|
};
|
|
85716
87366
|
};
|
|
@@ -85770,13 +87420,15 @@ interface paths {
|
|
|
85770
87420
|
};
|
|
85771
87421
|
};
|
|
85772
87422
|
};
|
|
87423
|
+
put?: never;
|
|
87424
|
+
post?: never;
|
|
85773
87425
|
delete?: never;
|
|
85774
87426
|
options?: never;
|
|
85775
87427
|
head?: never;
|
|
85776
87428
|
patch?: never;
|
|
85777
87429
|
trace?: never;
|
|
85778
87430
|
};
|
|
85779
|
-
"/clinic/agenda/
|
|
87431
|
+
"/clinic/agenda/free-hours": {
|
|
85780
87432
|
parameters: {
|
|
85781
87433
|
query?: never;
|
|
85782
87434
|
header?: never;
|
|
@@ -85784,25 +87436,17 @@ interface paths {
|
|
|
85784
87436
|
cookie?: never;
|
|
85785
87437
|
};
|
|
85786
87438
|
/**
|
|
85787
|
-
*
|
|
85788
|
-
* @description
|
|
87439
|
+
* Horas libres: one day of free hours per professional
|
|
87440
|
+
* @description Every free slot of `date` from the clinic's own booking engine (the same read as `GET /clinic/agenda/availability`, whole day), grouped per professional with back-to-back slots merged into `ranges` and `slots` = how many cupos. `especialidad` narrows to the professionals whose specialties or note name it; `especialidades` lists the roster's own, for a picker. `professional_id` is the Vitrina uuid when the roster knows them. For a Dentalink / Medilink clinic this is one live vendor request per call (rate-limited upstream), so read it on demand rather than on a timer. A past day has no free hours.
|
|
85789
87441
|
*
|
|
85790
87442
|
* **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`.
|
|
85791
87443
|
*/
|
|
85792
87444
|
get: {
|
|
85793
87445
|
parameters: {
|
|
85794
87446
|
query: {
|
|
85795
|
-
|
|
85796
|
-
|
|
85797
|
-
professional_id?: string;
|
|
87447
|
+
date: string;
|
|
87448
|
+
especialidad?: string;
|
|
85798
87449
|
location_id?: string;
|
|
85799
|
-
resource_id?: string;
|
|
85800
|
-
status?: ("pending_hold" | "confirmed" | "cancelled" | "completed" | "no_show")[];
|
|
85801
|
-
kind?: ("test_drive" | "external" | "block" | "clinic")[];
|
|
85802
|
-
/** @description Origen of the patient: `meta` (came from a Meta ad), `organic` (a linked contact with no ad touch) or `unknown` («Sin dato»: no linked contact). Same attribution as Vitrina Ads' people from ads. */
|
|
85803
|
-
origin?: "meta" | "organic" | "unknown";
|
|
85804
|
-
/** @description Narrow `origin=meta` to one Meta ad (its platform ad id). */
|
|
85805
|
-
origin_ad_id?: string;
|
|
85806
87450
|
};
|
|
85807
87451
|
header?: never;
|
|
85808
87452
|
path?: never;
|
|
@@ -85810,7 +87454,7 @@ interface paths {
|
|
|
85810
87454
|
};
|
|
85811
87455
|
requestBody?: never;
|
|
85812
87456
|
responses: {
|
|
85813
|
-
/** @description
|
|
87457
|
+
/** @description Free hours */
|
|
85814
87458
|
200: {
|
|
85815
87459
|
headers: {
|
|
85816
87460
|
[name: string]: unknown;
|
|
@@ -85818,61 +87462,37 @@ interface paths {
|
|
|
85818
87462
|
content: {
|
|
85819
87463
|
/**
|
|
85820
87464
|
* @example {
|
|
85821
|
-
* "data":
|
|
85822
|
-
*
|
|
85823
|
-
*
|
|
85824
|
-
*
|
|
85825
|
-
*
|
|
85826
|
-
*
|
|
85827
|
-
*
|
|
85828
|
-
*
|
|
85829
|
-
*
|
|
85830
|
-
*
|
|
85831
|
-
*
|
|
85832
|
-
*
|
|
85833
|
-
*
|
|
85834
|
-
*
|
|
85835
|
-
*
|
|
85836
|
-
*
|
|
85837
|
-
*
|
|
85838
|
-
*
|
|
85839
|
-
*
|
|
85840
|
-
*
|
|
85841
|
-
*
|
|
85842
|
-
*
|
|
85843
|
-
* "resource": null,
|
|
85844
|
-
* "service": null,
|
|
85845
|
-
* "patient": {
|
|
85846
|
-
* "id": "12121212-0000-4000-8000-000000000001",
|
|
85847
|
-
* "name": "María José Fuentes Lagos",
|
|
85848
|
-
* "external_id": null
|
|
85849
|
-
* },
|
|
85850
|
-
* "contact": {
|
|
85851
|
-
* "id": "22222222-0000-4000-8000-000000000001",
|
|
85852
|
-
* "name": "María José Fuentes Lagos"
|
|
85853
|
-
* },
|
|
85854
|
-
* "customer_name": "María José Fuentes Lagos",
|
|
85855
|
-
* "notes": "Avisar al +56987654321 si se atrasa",
|
|
85856
|
-
* "money": null,
|
|
85857
|
-
* "booking_kind": "new",
|
|
85858
|
-
* "flags": [
|
|
85859
|
-
* {
|
|
85860
|
-
* "id": "13131313-0000-4000-8000-000000000001",
|
|
85861
|
-
* "kind": "alergia",
|
|
85862
|
-
* "label": "Alergia a penicilina",
|
|
85863
|
-
* "severity": "severa"
|
|
85864
|
-
* }
|
|
85865
|
-
* ],
|
|
85866
|
-
* "vendor": {
|
|
85867
|
-
* "professional_id": null,
|
|
85868
|
-
* "professional_name": null,
|
|
85869
|
-
* "sucursal_id": null,
|
|
85870
|
-
* "agenda_id": null,
|
|
85871
|
-
* "sillon": null,
|
|
85872
|
-
* "status_code": null
|
|
87465
|
+
* "data": {
|
|
87466
|
+
* "date": "2026-09-24",
|
|
87467
|
+
* "engine": "native-clinic",
|
|
87468
|
+
* "timezone": "America/Santiago",
|
|
87469
|
+
* "especialidad": null,
|
|
87470
|
+
* "professionals": [
|
|
87471
|
+
* {
|
|
87472
|
+
* "professional_id": "ffffffff-0000-4000-8000-000000000001",
|
|
87473
|
+
* "engine_professional_id": "ffffffff-0000-4000-8000-000000000001",
|
|
87474
|
+
* "name": "Ana Rojas",
|
|
87475
|
+
* "especialidad": "Implantología",
|
|
87476
|
+
* "ranges": [
|
|
87477
|
+
* {
|
|
87478
|
+
* "starts_at": "2026-09-24T12:00:00.000Z",
|
|
87479
|
+
* "ends_at": "2026-09-24T13:30:00.000Z"
|
|
87480
|
+
* },
|
|
87481
|
+
* {
|
|
87482
|
+
* "starts_at": "2026-09-24T17:00:00.000Z",
|
|
87483
|
+
* "ends_at": "2026-09-24T18:00:00.000Z"
|
|
87484
|
+
* }
|
|
87485
|
+
* ],
|
|
87486
|
+
* "slots": 5
|
|
85873
87487
|
* }
|
|
85874
|
-
*
|
|
85875
|
-
*
|
|
87488
|
+
* ],
|
|
87489
|
+
* "especialidades": [
|
|
87490
|
+
* "Endodoncia",
|
|
87491
|
+
* "Implantología",
|
|
87492
|
+
* "Ortodoncia"
|
|
87493
|
+
* ],
|
|
87494
|
+
* "truncated": false
|
|
87495
|
+
* }
|
|
85876
87496
|
* }
|
|
85877
87497
|
*/
|
|
85878
87498
|
"application/json": {
|
|
@@ -87677,6 +89297,149 @@ interface paths {
|
|
|
87677
89297
|
patch?: never;
|
|
87678
89298
|
trace?: never;
|
|
87679
89299
|
};
|
|
89300
|
+
"/clinic/encounters/{id}/void": {
|
|
89301
|
+
parameters: {
|
|
89302
|
+
query?: never;
|
|
89303
|
+
header?: never;
|
|
89304
|
+
path?: never;
|
|
89305
|
+
cookie?: never;
|
|
89306
|
+
};
|
|
89307
|
+
get?: never;
|
|
89308
|
+
put?: never;
|
|
89309
|
+
/**
|
|
89310
|
+
* Void an atención (idempotent)
|
|
89311
|
+
* @description Voids an atención opened or closed in error; the row stays, with its reason. Voiding an already voided atención returns it unchanged. Refused on a locked atención. The cita lines that closing performed go back to not performed, so their insumos return to stock. The reason is not copied into the audit row. Every call writes a `clinic_record_access_log` row; a call that cannot write its access event fails.
|
|
89312
|
+
*
|
|
89313
|
+
* **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.
|
|
89314
|
+
*/
|
|
89315
|
+
post: {
|
|
89316
|
+
parameters: {
|
|
89317
|
+
query?: never;
|
|
89318
|
+
header?: {
|
|
89319
|
+
/** @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. */
|
|
89320
|
+
"Idempotency-Key"?: string;
|
|
89321
|
+
};
|
|
89322
|
+
path: {
|
|
89323
|
+
id: string;
|
|
89324
|
+
};
|
|
89325
|
+
cookie?: never;
|
|
89326
|
+
};
|
|
89327
|
+
requestBody: {
|
|
89328
|
+
content: {
|
|
89329
|
+
/**
|
|
89330
|
+
* @example {
|
|
89331
|
+
* "reason": "Abierta por error"
|
|
89332
|
+
* }
|
|
89333
|
+
*/
|
|
89334
|
+
"application/json": {
|
|
89335
|
+
reason: string;
|
|
89336
|
+
};
|
|
89337
|
+
};
|
|
89338
|
+
};
|
|
89339
|
+
responses: {
|
|
89340
|
+
/** @description Atención */
|
|
89341
|
+
200: {
|
|
89342
|
+
headers: {
|
|
89343
|
+
[name: string]: unknown;
|
|
89344
|
+
};
|
|
89345
|
+
content: {
|
|
89346
|
+
/**
|
|
89347
|
+
* @example {
|
|
89348
|
+
* "data": {
|
|
89349
|
+
* "id": "e0e57121-0000-4000-8000-0000000007ab",
|
|
89350
|
+
* "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
|
|
89351
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
89352
|
+
* "appointment_id": "d93e8eec-0000-4000-8000-000000000001",
|
|
89353
|
+
* "professional_id": null,
|
|
89354
|
+
* "location_id": null,
|
|
89355
|
+
* "treatment_plan_id": null,
|
|
89356
|
+
* "form_template_id": null,
|
|
89357
|
+
* "sterilization_lote": null,
|
|
89358
|
+
* "kind": "control",
|
|
89359
|
+
* "status": "voided",
|
|
89360
|
+
* "starts_at": "2026-10-09T18:00:00.000Z",
|
|
89361
|
+
* "ends_at": null,
|
|
89362
|
+
* "closed_at": "2026-10-09T18:40:00.000Z",
|
|
89363
|
+
* "opened_by_user_id": "5e5e5e5e-0000-4000-8000-000000000001",
|
|
89364
|
+
* "closed_by_user_id": "5e5e5e5e-0000-4000-8000-000000000001",
|
|
89365
|
+
* "voided_reason": "Abierta por error",
|
|
89366
|
+
* "author": null,
|
|
89367
|
+
* "created_at": "2026-10-09T18:00:00.000Z",
|
|
89368
|
+
* "updated_at": "2026-10-09T18:45:00.000Z",
|
|
89369
|
+
* "notes": []
|
|
89370
|
+
* }
|
|
89371
|
+
* }
|
|
89372
|
+
*/
|
|
89373
|
+
"application/json": {
|
|
89374
|
+
data?: unknown;
|
|
89375
|
+
meta?: {
|
|
89376
|
+
[key: string]: unknown;
|
|
89377
|
+
};
|
|
89378
|
+
};
|
|
89379
|
+
};
|
|
89380
|
+
};
|
|
89381
|
+
/** @description Validation error */
|
|
89382
|
+
400: {
|
|
89383
|
+
headers: {
|
|
89384
|
+
[name: string]: unknown;
|
|
89385
|
+
};
|
|
89386
|
+
content: {
|
|
89387
|
+
"application/json": components["schemas"]["Error"];
|
|
89388
|
+
};
|
|
89389
|
+
};
|
|
89390
|
+
/** @description Unauthorized */
|
|
89391
|
+
401: {
|
|
89392
|
+
headers: {
|
|
89393
|
+
[name: string]: unknown;
|
|
89394
|
+
};
|
|
89395
|
+
content: {
|
|
89396
|
+
"application/json": components["schemas"]["Error"];
|
|
89397
|
+
};
|
|
89398
|
+
};
|
|
89399
|
+
/** @description Forbidden */
|
|
89400
|
+
403: {
|
|
89401
|
+
headers: {
|
|
89402
|
+
[name: string]: unknown;
|
|
89403
|
+
};
|
|
89404
|
+
content: {
|
|
89405
|
+
"application/json": components["schemas"]["Error"];
|
|
89406
|
+
};
|
|
89407
|
+
};
|
|
89408
|
+
/** @description Not found */
|
|
89409
|
+
404: {
|
|
89410
|
+
headers: {
|
|
89411
|
+
[name: string]: unknown;
|
|
89412
|
+
};
|
|
89413
|
+
content: {
|
|
89414
|
+
"application/json": components["schemas"]["Error"];
|
|
89415
|
+
};
|
|
89416
|
+
};
|
|
89417
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
89418
|
+
409: {
|
|
89419
|
+
headers: {
|
|
89420
|
+
[name: string]: unknown;
|
|
89421
|
+
};
|
|
89422
|
+
content: {
|
|
89423
|
+
"application/json": components["schemas"]["Error"];
|
|
89424
|
+
};
|
|
89425
|
+
};
|
|
89426
|
+
/** @description Rate limited */
|
|
89427
|
+
429: {
|
|
89428
|
+
headers: {
|
|
89429
|
+
[name: string]: unknown;
|
|
89430
|
+
};
|
|
89431
|
+
content: {
|
|
89432
|
+
"application/json": components["schemas"]["Error"];
|
|
89433
|
+
};
|
|
89434
|
+
};
|
|
89435
|
+
};
|
|
89436
|
+
};
|
|
89437
|
+
delete?: never;
|
|
89438
|
+
options?: never;
|
|
89439
|
+
head?: never;
|
|
89440
|
+
patch?: never;
|
|
89441
|
+
trace?: never;
|
|
89442
|
+
};
|
|
87680
89443
|
"/clinic/encounters/{id}/sterilization-lote": {
|
|
87681
89444
|
parameters: {
|
|
87682
89445
|
query?: never;
|
|
@@ -98135,45 +99898,554 @@ interface paths {
|
|
|
98135
99898
|
options?: never;
|
|
98136
99899
|
head?: never;
|
|
98137
99900
|
/**
|
|
98138
|
-
* Edit one family bond
|
|
98139
|
-
* @description Partial update. Promoting a bond to `is_primary` demotes the incumbent first (the partial unique index allows exactly one per patient). Raising `can_read_record` needs `clinic_record:write`; lowering it never does — revoking access is always safe.
|
|
99901
|
+
* Edit one family bond
|
|
99902
|
+
* @description Partial update. Promoting a bond to `is_primary` demotes the incumbent first (the partial unique index allows exactly one per patient). Raising `can_read_record` needs `clinic_record:write`; lowering it never does — revoking access is always safe.
|
|
99903
|
+
*
|
|
99904
|
+
* **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.
|
|
99905
|
+
*/
|
|
99906
|
+
patch: {
|
|
99907
|
+
parameters: {
|
|
99908
|
+
query?: never;
|
|
99909
|
+
header?: never;
|
|
99910
|
+
path: {
|
|
99911
|
+
id: string;
|
|
99912
|
+
};
|
|
99913
|
+
cookie?: never;
|
|
99914
|
+
};
|
|
99915
|
+
requestBody?: {
|
|
99916
|
+
content: {
|
|
99917
|
+
/**
|
|
99918
|
+
* @example {
|
|
99919
|
+
* "can_read_record": false
|
|
99920
|
+
* }
|
|
99921
|
+
*/
|
|
99922
|
+
"application/json": {
|
|
99923
|
+
/** Format: uuid */
|
|
99924
|
+
related_patient_id?: string | null;
|
|
99925
|
+
/** @enum {string} */
|
|
99926
|
+
role?: "titular" | "apoderado" | "tutor" | "carga" | "pareja" | "otro";
|
|
99927
|
+
is_primary?: boolean;
|
|
99928
|
+
can_book?: boolean;
|
|
99929
|
+
can_read_record?: boolean;
|
|
99930
|
+
/** @enum {string} */
|
|
99931
|
+
verified_method?: "phone_match" | "id_challenge" | "manual" | "document";
|
|
99932
|
+
/** Format: date-time */
|
|
99933
|
+
expires_at?: string | null;
|
|
99934
|
+
note?: string | null;
|
|
99935
|
+
};
|
|
99936
|
+
};
|
|
99937
|
+
};
|
|
99938
|
+
responses: {
|
|
99939
|
+
/** @description Relationship */
|
|
99940
|
+
200: {
|
|
99941
|
+
headers: {
|
|
99942
|
+
[name: string]: unknown;
|
|
99943
|
+
};
|
|
99944
|
+
content: {
|
|
99945
|
+
/**
|
|
99946
|
+
* @example {
|
|
99947
|
+
* "data": {
|
|
99948
|
+
* "id": "6a73a912-0000-4000-8000-000000000002",
|
|
99949
|
+
* "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
|
|
99950
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
99951
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000002",
|
|
99952
|
+
* "related_patient_id": null,
|
|
99953
|
+
* "role": "apoderado",
|
|
99954
|
+
* "is_primary": false,
|
|
99955
|
+
* "can_book": true,
|
|
99956
|
+
* "can_read_record": false,
|
|
99957
|
+
* "verified_method": "id_challenge",
|
|
99958
|
+
* "verified_at": "2026-09-22T22:21:17.284Z",
|
|
99959
|
+
* "expires_at": null,
|
|
99960
|
+
* "note": "Presentó cédula en el mesón",
|
|
99961
|
+
* "created_by": null,
|
|
99962
|
+
* "created_at": "2026-09-22T22:21:17.283Z",
|
|
99963
|
+
* "updated_at": "2026-09-22T22:21:17.298Z",
|
|
99964
|
+
* "contact_name": "Carmen Lagos Pinto",
|
|
99965
|
+
* "contact_phone": "+56955554444",
|
|
99966
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
99967
|
+
* "expired": false
|
|
99968
|
+
* }
|
|
99969
|
+
* }
|
|
99970
|
+
*/
|
|
99971
|
+
"application/json": {
|
|
99972
|
+
data?: unknown;
|
|
99973
|
+
meta?: {
|
|
99974
|
+
[key: string]: unknown;
|
|
99975
|
+
};
|
|
99976
|
+
};
|
|
99977
|
+
};
|
|
99978
|
+
};
|
|
99979
|
+
/** @description Validation error */
|
|
99980
|
+
400: {
|
|
99981
|
+
headers: {
|
|
99982
|
+
[name: string]: unknown;
|
|
99983
|
+
};
|
|
99984
|
+
content: {
|
|
99985
|
+
"application/json": components["schemas"]["Error"];
|
|
99986
|
+
};
|
|
99987
|
+
};
|
|
99988
|
+
/** @description Unauthorized */
|
|
99989
|
+
401: {
|
|
99990
|
+
headers: {
|
|
99991
|
+
[name: string]: unknown;
|
|
99992
|
+
};
|
|
99993
|
+
content: {
|
|
99994
|
+
"application/json": components["schemas"]["Error"];
|
|
99995
|
+
};
|
|
99996
|
+
};
|
|
99997
|
+
/** @description Forbidden */
|
|
99998
|
+
403: {
|
|
99999
|
+
headers: {
|
|
100000
|
+
[name: string]: unknown;
|
|
100001
|
+
};
|
|
100002
|
+
content: {
|
|
100003
|
+
"application/json": components["schemas"]["Error"];
|
|
100004
|
+
};
|
|
100005
|
+
};
|
|
100006
|
+
/** @description Not found */
|
|
100007
|
+
404: {
|
|
100008
|
+
headers: {
|
|
100009
|
+
[name: string]: unknown;
|
|
100010
|
+
};
|
|
100011
|
+
content: {
|
|
100012
|
+
"application/json": components["schemas"]["Error"];
|
|
100013
|
+
};
|
|
100014
|
+
};
|
|
100015
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
100016
|
+
409: {
|
|
100017
|
+
headers: {
|
|
100018
|
+
[name: string]: unknown;
|
|
100019
|
+
};
|
|
100020
|
+
content: {
|
|
100021
|
+
"application/json": components["schemas"]["Error"];
|
|
100022
|
+
};
|
|
100023
|
+
};
|
|
100024
|
+
/** @description Rate limited */
|
|
100025
|
+
429: {
|
|
100026
|
+
headers: {
|
|
100027
|
+
[name: string]: unknown;
|
|
100028
|
+
};
|
|
100029
|
+
content: {
|
|
100030
|
+
"application/json": components["schemas"]["Error"];
|
|
100031
|
+
};
|
|
100032
|
+
};
|
|
100033
|
+
};
|
|
100034
|
+
};
|
|
100035
|
+
trace?: never;
|
|
100036
|
+
};
|
|
100037
|
+
"/clinic/patients/{id}/auto-links": {
|
|
100038
|
+
parameters: {
|
|
100039
|
+
query?: never;
|
|
100040
|
+
header?: never;
|
|
100041
|
+
path?: never;
|
|
100042
|
+
cookie?: never;
|
|
100043
|
+
};
|
|
100044
|
+
/**
|
|
100045
|
+
* Automatic contact links of a patient (Ads identity only)
|
|
100046
|
+
* @description The contacts Vitrina matched to this ficha AUTOMATICALLY for Ads outcomes: an E.164 phone or an exact email held by exactly one patient and exactly one contact of the clinic, the patient an adult with a plausible birth date and not a carga, and no family bond or booking link on either side. It is identity for Ads only — it grants no booking and no access to the clinical record, and a family bond or a booking link always outranks it. Each row: `id`, `clinic_patient_id`, `contact_id`, `patient_name`, `contact_name`, `status` (`live` | `revoked` — a run found it no longer unique or ineligible — | `rejected` — a person said it is not this person, never re-opened), `method` (`phone_unique` | `email_unique`: which identifier was held by exactly one patient and one contact; `chat_rut`: the patient's RUT typed by exactly one contact in its own ad chat, corroborated by the typed email or by the ficha appearing after it — the value itself is never stored), `matched_at`, `run_id` (the matching run, provenance), `revoked_at`, `revoked_reason`, `sent_count` / `last_sent_at` (Ads outcomes sent under the pair). Live first.
|
|
100047
|
+
*
|
|
100048
|
+
* **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.
|
|
100049
|
+
*/
|
|
100050
|
+
get: {
|
|
100051
|
+
parameters: {
|
|
100052
|
+
query?: never;
|
|
100053
|
+
header?: never;
|
|
100054
|
+
path: {
|
|
100055
|
+
id: string;
|
|
100056
|
+
};
|
|
100057
|
+
cookie?: never;
|
|
100058
|
+
};
|
|
100059
|
+
requestBody?: never;
|
|
100060
|
+
responses: {
|
|
100061
|
+
/** @description Patient auto-links */
|
|
100062
|
+
200: {
|
|
100063
|
+
headers: {
|
|
100064
|
+
[name: string]: unknown;
|
|
100065
|
+
};
|
|
100066
|
+
content: {
|
|
100067
|
+
/**
|
|
100068
|
+
* @example {
|
|
100069
|
+
* "data": {
|
|
100070
|
+
* "data": [
|
|
100071
|
+
* {
|
|
100072
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
100073
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
100074
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
100075
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
100076
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
100077
|
+
* "status": "live",
|
|
100078
|
+
* "method": "phone_unique",
|
|
100079
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
100080
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
100081
|
+
* "revoked_at": null,
|
|
100082
|
+
* "revoked_reason": null,
|
|
100083
|
+
* "sent_count": 3,
|
|
100084
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z"
|
|
100085
|
+
* }
|
|
100086
|
+
* ]
|
|
100087
|
+
* }
|
|
100088
|
+
* }
|
|
100089
|
+
*/
|
|
100090
|
+
"application/json": {
|
|
100091
|
+
data?: unknown;
|
|
100092
|
+
meta?: {
|
|
100093
|
+
[key: string]: unknown;
|
|
100094
|
+
};
|
|
100095
|
+
};
|
|
100096
|
+
};
|
|
100097
|
+
};
|
|
100098
|
+
/** @description Validation error */
|
|
100099
|
+
400: {
|
|
100100
|
+
headers: {
|
|
100101
|
+
[name: string]: unknown;
|
|
100102
|
+
};
|
|
100103
|
+
content: {
|
|
100104
|
+
"application/json": components["schemas"]["Error"];
|
|
100105
|
+
};
|
|
100106
|
+
};
|
|
100107
|
+
/** @description Unauthorized */
|
|
100108
|
+
401: {
|
|
100109
|
+
headers: {
|
|
100110
|
+
[name: string]: unknown;
|
|
100111
|
+
};
|
|
100112
|
+
content: {
|
|
100113
|
+
"application/json": components["schemas"]["Error"];
|
|
100114
|
+
};
|
|
100115
|
+
};
|
|
100116
|
+
/** @description Forbidden */
|
|
100117
|
+
403: {
|
|
100118
|
+
headers: {
|
|
100119
|
+
[name: string]: unknown;
|
|
100120
|
+
};
|
|
100121
|
+
content: {
|
|
100122
|
+
"application/json": components["schemas"]["Error"];
|
|
100123
|
+
};
|
|
100124
|
+
};
|
|
100125
|
+
/** @description Not found */
|
|
100126
|
+
404: {
|
|
100127
|
+
headers: {
|
|
100128
|
+
[name: string]: unknown;
|
|
100129
|
+
};
|
|
100130
|
+
content: {
|
|
100131
|
+
"application/json": components["schemas"]["Error"];
|
|
100132
|
+
};
|
|
100133
|
+
};
|
|
100134
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
100135
|
+
409: {
|
|
100136
|
+
headers: {
|
|
100137
|
+
[name: string]: unknown;
|
|
100138
|
+
};
|
|
100139
|
+
content: {
|
|
100140
|
+
"application/json": components["schemas"]["Error"];
|
|
100141
|
+
};
|
|
100142
|
+
};
|
|
100143
|
+
/** @description Rate limited */
|
|
100144
|
+
429: {
|
|
100145
|
+
headers: {
|
|
100146
|
+
[name: string]: unknown;
|
|
100147
|
+
};
|
|
100148
|
+
content: {
|
|
100149
|
+
"application/json": components["schemas"]["Error"];
|
|
100150
|
+
};
|
|
100151
|
+
};
|
|
100152
|
+
};
|
|
100153
|
+
};
|
|
100154
|
+
put?: never;
|
|
100155
|
+
post?: never;
|
|
100156
|
+
delete?: never;
|
|
100157
|
+
options?: never;
|
|
100158
|
+
head?: never;
|
|
100159
|
+
patch?: never;
|
|
100160
|
+
trace?: never;
|
|
100161
|
+
};
|
|
100162
|
+
"/clinic/contacts/{contactId}/auto-links": {
|
|
100163
|
+
parameters: {
|
|
100164
|
+
query?: never;
|
|
100165
|
+
header?: never;
|
|
100166
|
+
path?: never;
|
|
100167
|
+
cookie?: never;
|
|
100168
|
+
};
|
|
100169
|
+
/**
|
|
100170
|
+
* Patients automatically linked to a contact (Ads identity only)
|
|
100171
|
+
* @description The contact side of the same automatic links — what the contact ficha shows as «Vinculado automáticamente». An empty list, not a 404, when there is none. Each row: `id`, `clinic_patient_id`, `contact_id`, `patient_name`, `contact_name`, `status` (`live` | `revoked` — a run found it no longer unique or ineligible — | `rejected` — a person said it is not this person, never re-opened), `method` (`phone_unique` | `email_unique`: which identifier was held by exactly one patient and one contact; `chat_rut`: the patient's RUT typed by exactly one contact in its own ad chat, corroborated by the typed email or by the ficha appearing after it — the value itself is never stored), `matched_at`, `run_id` (the matching run, provenance), `revoked_at`, `revoked_reason`, `sent_count` / `last_sent_at` (Ads outcomes sent under the pair). Live first.
|
|
100172
|
+
*
|
|
100173
|
+
* **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.
|
|
100174
|
+
*/
|
|
100175
|
+
get: {
|
|
100176
|
+
parameters: {
|
|
100177
|
+
query?: never;
|
|
100178
|
+
header?: never;
|
|
100179
|
+
path: {
|
|
100180
|
+
contactId: string;
|
|
100181
|
+
};
|
|
100182
|
+
cookie?: never;
|
|
100183
|
+
};
|
|
100184
|
+
requestBody?: never;
|
|
100185
|
+
responses: {
|
|
100186
|
+
/** @description Contact auto-links */
|
|
100187
|
+
200: {
|
|
100188
|
+
headers: {
|
|
100189
|
+
[name: string]: unknown;
|
|
100190
|
+
};
|
|
100191
|
+
content: {
|
|
100192
|
+
/**
|
|
100193
|
+
* @example {
|
|
100194
|
+
* "data": {
|
|
100195
|
+
* "data": [
|
|
100196
|
+
* {
|
|
100197
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
100198
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
100199
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
100200
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
100201
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
100202
|
+
* "status": "live",
|
|
100203
|
+
* "method": "phone_unique",
|
|
100204
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
100205
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
100206
|
+
* "revoked_at": null,
|
|
100207
|
+
* "revoked_reason": null,
|
|
100208
|
+
* "sent_count": 3,
|
|
100209
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z"
|
|
100210
|
+
* }
|
|
100211
|
+
* ]
|
|
100212
|
+
* }
|
|
100213
|
+
* }
|
|
100214
|
+
*/
|
|
100215
|
+
"application/json": {
|
|
100216
|
+
data?: unknown;
|
|
100217
|
+
meta?: {
|
|
100218
|
+
[key: string]: unknown;
|
|
100219
|
+
};
|
|
100220
|
+
};
|
|
100221
|
+
};
|
|
100222
|
+
};
|
|
100223
|
+
/** @description Validation error */
|
|
100224
|
+
400: {
|
|
100225
|
+
headers: {
|
|
100226
|
+
[name: string]: unknown;
|
|
100227
|
+
};
|
|
100228
|
+
content: {
|
|
100229
|
+
"application/json": components["schemas"]["Error"];
|
|
100230
|
+
};
|
|
100231
|
+
};
|
|
100232
|
+
/** @description Unauthorized */
|
|
100233
|
+
401: {
|
|
100234
|
+
headers: {
|
|
100235
|
+
[name: string]: unknown;
|
|
100236
|
+
};
|
|
100237
|
+
content: {
|
|
100238
|
+
"application/json": components["schemas"]["Error"];
|
|
100239
|
+
};
|
|
100240
|
+
};
|
|
100241
|
+
/** @description Forbidden */
|
|
100242
|
+
403: {
|
|
100243
|
+
headers: {
|
|
100244
|
+
[name: string]: unknown;
|
|
100245
|
+
};
|
|
100246
|
+
content: {
|
|
100247
|
+
"application/json": components["schemas"]["Error"];
|
|
100248
|
+
};
|
|
100249
|
+
};
|
|
100250
|
+
/** @description Not found */
|
|
100251
|
+
404: {
|
|
100252
|
+
headers: {
|
|
100253
|
+
[name: string]: unknown;
|
|
100254
|
+
};
|
|
100255
|
+
content: {
|
|
100256
|
+
"application/json": components["schemas"]["Error"];
|
|
100257
|
+
};
|
|
100258
|
+
};
|
|
100259
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
100260
|
+
409: {
|
|
100261
|
+
headers: {
|
|
100262
|
+
[name: string]: unknown;
|
|
100263
|
+
};
|
|
100264
|
+
content: {
|
|
100265
|
+
"application/json": components["schemas"]["Error"];
|
|
100266
|
+
};
|
|
100267
|
+
};
|
|
100268
|
+
/** @description Rate limited */
|
|
100269
|
+
429: {
|
|
100270
|
+
headers: {
|
|
100271
|
+
[name: string]: unknown;
|
|
100272
|
+
};
|
|
100273
|
+
content: {
|
|
100274
|
+
"application/json": components["schemas"]["Error"];
|
|
100275
|
+
};
|
|
100276
|
+
};
|
|
100277
|
+
};
|
|
100278
|
+
};
|
|
100279
|
+
put?: never;
|
|
100280
|
+
post?: never;
|
|
100281
|
+
delete?: never;
|
|
100282
|
+
options?: never;
|
|
100283
|
+
head?: never;
|
|
100284
|
+
patch?: never;
|
|
100285
|
+
trace?: never;
|
|
100286
|
+
};
|
|
100287
|
+
"/clinic/auto-links/{id}/reject": {
|
|
100288
|
+
parameters: {
|
|
100289
|
+
query?: never;
|
|
100290
|
+
header?: never;
|
|
100291
|
+
path?: never;
|
|
100292
|
+
cookie?: never;
|
|
100293
|
+
};
|
|
100294
|
+
get?: never;
|
|
100295
|
+
put?: never;
|
|
100296
|
+
/**
|
|
100297
|
+
* «No es esta persona» — reject an automatic link for good
|
|
100298
|
+
* @description Marks the pair `rejected`: no later matching run re-opens it, and the Ads outcomes sent under it that have not left Vitrina yet are withheld (`withheld_outcomes` says how many). What already reached the ad platforms is not recalled. Idempotent. Answers the row. 404 when the id is not this clinic’s.
|
|
100299
|
+
*
|
|
100300
|
+
* **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.
|
|
100301
|
+
*/
|
|
100302
|
+
post: {
|
|
100303
|
+
parameters: {
|
|
100304
|
+
query?: never;
|
|
100305
|
+
header?: {
|
|
100306
|
+
/** @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. */
|
|
100307
|
+
"Idempotency-Key"?: string;
|
|
100308
|
+
};
|
|
100309
|
+
path: {
|
|
100310
|
+
id: string;
|
|
100311
|
+
};
|
|
100312
|
+
cookie?: never;
|
|
100313
|
+
};
|
|
100314
|
+
requestBody?: {
|
|
100315
|
+
content: {
|
|
100316
|
+
/** @example {} */
|
|
100317
|
+
"application/json": Record<string, never>;
|
|
100318
|
+
};
|
|
100319
|
+
};
|
|
100320
|
+
responses: {
|
|
100321
|
+
/** @description Rejected auto-link */
|
|
100322
|
+
200: {
|
|
100323
|
+
headers: {
|
|
100324
|
+
[name: string]: unknown;
|
|
100325
|
+
};
|
|
100326
|
+
content: {
|
|
100327
|
+
/**
|
|
100328
|
+
* @example {
|
|
100329
|
+
* "data": {
|
|
100330
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
100331
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
100332
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
100333
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
100334
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
100335
|
+
* "status": "rejected",
|
|
100336
|
+
* "method": "phone_unique",
|
|
100337
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
100338
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
100339
|
+
* "revoked_at": "2026-09-28T15:31:09.004Z",
|
|
100340
|
+
* "revoked_reason": "rejected",
|
|
100341
|
+
* "sent_count": 3,
|
|
100342
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z",
|
|
100343
|
+
* "withheld_outcomes": 1
|
|
100344
|
+
* }
|
|
100345
|
+
* }
|
|
100346
|
+
*/
|
|
100347
|
+
"application/json": {
|
|
100348
|
+
data?: unknown;
|
|
100349
|
+
meta?: {
|
|
100350
|
+
[key: string]: unknown;
|
|
100351
|
+
};
|
|
100352
|
+
};
|
|
100353
|
+
};
|
|
100354
|
+
};
|
|
100355
|
+
/** @description Validation error */
|
|
100356
|
+
400: {
|
|
100357
|
+
headers: {
|
|
100358
|
+
[name: string]: unknown;
|
|
100359
|
+
};
|
|
100360
|
+
content: {
|
|
100361
|
+
"application/json": components["schemas"]["Error"];
|
|
100362
|
+
};
|
|
100363
|
+
};
|
|
100364
|
+
/** @description Unauthorized */
|
|
100365
|
+
401: {
|
|
100366
|
+
headers: {
|
|
100367
|
+
[name: string]: unknown;
|
|
100368
|
+
};
|
|
100369
|
+
content: {
|
|
100370
|
+
"application/json": components["schemas"]["Error"];
|
|
100371
|
+
};
|
|
100372
|
+
};
|
|
100373
|
+
/** @description Forbidden */
|
|
100374
|
+
403: {
|
|
100375
|
+
headers: {
|
|
100376
|
+
[name: string]: unknown;
|
|
100377
|
+
};
|
|
100378
|
+
content: {
|
|
100379
|
+
"application/json": components["schemas"]["Error"];
|
|
100380
|
+
};
|
|
100381
|
+
};
|
|
100382
|
+
/** @description Not found */
|
|
100383
|
+
404: {
|
|
100384
|
+
headers: {
|
|
100385
|
+
[name: string]: unknown;
|
|
100386
|
+
};
|
|
100387
|
+
content: {
|
|
100388
|
+
"application/json": components["schemas"]["Error"];
|
|
100389
|
+
};
|
|
100390
|
+
};
|
|
100391
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
100392
|
+
409: {
|
|
100393
|
+
headers: {
|
|
100394
|
+
[name: string]: unknown;
|
|
100395
|
+
};
|
|
100396
|
+
content: {
|
|
100397
|
+
"application/json": components["schemas"]["Error"];
|
|
100398
|
+
};
|
|
100399
|
+
};
|
|
100400
|
+
/** @description Rate limited */
|
|
100401
|
+
429: {
|
|
100402
|
+
headers: {
|
|
100403
|
+
[name: string]: unknown;
|
|
100404
|
+
};
|
|
100405
|
+
content: {
|
|
100406
|
+
"application/json": components["schemas"]["Error"];
|
|
100407
|
+
};
|
|
100408
|
+
};
|
|
100409
|
+
};
|
|
100410
|
+
};
|
|
100411
|
+
delete?: never;
|
|
100412
|
+
options?: never;
|
|
100413
|
+
head?: never;
|
|
100414
|
+
patch?: never;
|
|
100415
|
+
trace?: never;
|
|
100416
|
+
};
|
|
100417
|
+
"/clinic/insights/produccion": {
|
|
100418
|
+
parameters: {
|
|
100419
|
+
query?: never;
|
|
100420
|
+
header?: never;
|
|
100421
|
+
path?: never;
|
|
100422
|
+
cookie?: never;
|
|
100423
|
+
};
|
|
100424
|
+
/**
|
|
100425
|
+
* What was performed and what was collected
|
|
100426
|
+
* @description Producción, aggregates only. A Dentalink / Medilink clinic (revenue mirror on, `basis: mirror_lines`) reads the vendor's own plan lines marked realizado, by fecha de realización, at the line's total — Dentalink's «Ventas (acciones realizadas)», evaluación included, $0 lines out; `collected_clp` is every live payment received in the window (`null` with `professional_id`: a payment names no professional). Otherwise only ATTENDED citas count, valued from the cita's frozen `clinic_appointment_service` lines (a native clinic) or the catálogo's current price for the prestación the mirror names; `lines_without_price` names the hole, and `collected_clp` is what the ledger allocated to those citas. `by_professional` and the `professional_id` filter follow who PERFORMED the work, not who quoted the plan. Requires `clinic_money:read`; a caller holding only `clinic_insights:read` reads the last closed months with the minimum-count floor (`suppression`). Accepts `from` / `to` (bare `YYYY-MM-DD`, `to` INCLUSIVE), `location_id` and `professional_id`. The default window is the 90 days ending today in the clinic's own zone. A `professional_id` that is not yours is a 404, never an empty report. Also reachable with `clinic_insights:read` — the aggregates-only «Consultor» role (spec #2441 D11) — in addition to the scope named above. A caller WITHOUT the report’s own scope never receives a patient-identifiable row (`inasistencias.citas` and `packs.expiring` come back empty with `aggregate_only: true` and `rows_withheld` naming the field) and reads the minimum-count floor: always the last 3 closed calendar months with no professional or sucursal filter, whatever was asked (`suppression.filters_ignored`); a count or CLP resting on 1–4 cases is `null`; a rate over fewer than 5 cases, or whose numerator is withheld, is `null`; list rows that add up to a shown total get complementary suppression and leave the list (`suppression.withheld_rows`); per-professional/prestación/weekday outcome rows and per-channel confirmation rows carry rates only; producción serves no per-prestación rows (they nest inside the categorías); clinic-wide cash over whole months stays while its slices are floored. `suppression.min_count` is the floor.
|
|
98140
100427
|
*
|
|
98141
|
-
* **Connected apps:**
|
|
100428
|
+
* **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`.
|
|
98142
100429
|
*/
|
|
98143
|
-
|
|
100430
|
+
get: {
|
|
98144
100431
|
parameters: {
|
|
98145
|
-
query?:
|
|
98146
|
-
|
|
98147
|
-
|
|
98148
|
-
|
|
100432
|
+
query?: {
|
|
100433
|
+
/** @description First day of the window, inclusive. Defaults to 90 days before `to`. */
|
|
100434
|
+
from?: string;
|
|
100435
|
+
/** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
|
|
100436
|
+
to?: string;
|
|
100437
|
+
/** @description One sucursal. Omit for all of them. */
|
|
100438
|
+
location_id?: string;
|
|
100439
|
+
/** @description One profesional. A foreign id is a 404, never an empty report. */
|
|
100440
|
+
professional_id?: string;
|
|
98149
100441
|
};
|
|
100442
|
+
header?: never;
|
|
100443
|
+
path?: never;
|
|
98150
100444
|
cookie?: never;
|
|
98151
100445
|
};
|
|
98152
|
-
requestBody?:
|
|
98153
|
-
content: {
|
|
98154
|
-
/**
|
|
98155
|
-
* @example {
|
|
98156
|
-
* "can_read_record": false
|
|
98157
|
-
* }
|
|
98158
|
-
*/
|
|
98159
|
-
"application/json": {
|
|
98160
|
-
/** Format: uuid */
|
|
98161
|
-
related_patient_id?: string | null;
|
|
98162
|
-
/** @enum {string} */
|
|
98163
|
-
role?: "titular" | "apoderado" | "tutor" | "carga" | "pareja" | "otro";
|
|
98164
|
-
is_primary?: boolean;
|
|
98165
|
-
can_book?: boolean;
|
|
98166
|
-
can_read_record?: boolean;
|
|
98167
|
-
/** @enum {string} */
|
|
98168
|
-
verified_method?: "phone_match" | "id_challenge" | "manual" | "document";
|
|
98169
|
-
/** Format: date-time */
|
|
98170
|
-
expires_at?: string | null;
|
|
98171
|
-
note?: string | null;
|
|
98172
|
-
};
|
|
98173
|
-
};
|
|
98174
|
-
};
|
|
100446
|
+
requestBody?: never;
|
|
98175
100447
|
responses: {
|
|
98176
|
-
/** @description
|
|
100448
|
+
/** @description Clinic production report */
|
|
98177
100449
|
200: {
|
|
98178
100450
|
headers: {
|
|
98179
100451
|
[name: string]: unknown;
|
|
@@ -98182,34 +100454,59 @@ interface paths {
|
|
|
98182
100454
|
/**
|
|
98183
100455
|
* @example {
|
|
98184
100456
|
* "data": {
|
|
98185
|
-
* "
|
|
98186
|
-
* "
|
|
98187
|
-
* "
|
|
98188
|
-
* "
|
|
98189
|
-
* "
|
|
98190
|
-
* "
|
|
98191
|
-
*
|
|
98192
|
-
*
|
|
98193
|
-
*
|
|
98194
|
-
*
|
|
98195
|
-
*
|
|
98196
|
-
*
|
|
98197
|
-
*
|
|
98198
|
-
* "
|
|
98199
|
-
*
|
|
98200
|
-
*
|
|
98201
|
-
*
|
|
98202
|
-
*
|
|
98203
|
-
*
|
|
98204
|
-
*
|
|
100457
|
+
* "from": "2026-09-01",
|
|
100458
|
+
* "to": "2026-09-30",
|
|
100459
|
+
* "location_id": null,
|
|
100460
|
+
* "professional_id": null,
|
|
100461
|
+
* "basis": "mirror_lines",
|
|
100462
|
+
* "totals": {
|
|
100463
|
+
* "attended": 612,
|
|
100464
|
+
* "lines": 699,
|
|
100465
|
+
* "lines_without_price": 0,
|
|
100466
|
+
* "performed_clp": 57179516,
|
|
100467
|
+
* "collected_clp": 57172232,
|
|
100468
|
+
* "collected_basis": "mirror_payment.received"
|
|
100469
|
+
* },
|
|
100470
|
+
* "by_professional": [
|
|
100471
|
+
* {
|
|
100472
|
+
* "key": "00000000-0000-4000-8000-0000000000a1",
|
|
100473
|
+
* "label": "Ana Rojas",
|
|
100474
|
+
* "appointments": 141,
|
|
100475
|
+
* "lines": 168,
|
|
100476
|
+
* "performed_clp": 9623135
|
|
100477
|
+
* }
|
|
100478
|
+
* ],
|
|
100479
|
+
* "by_service": [
|
|
100480
|
+
* {
|
|
100481
|
+
* "key": "00000000-0000-4000-8000-0000000000b3",
|
|
100482
|
+
* "label": "Endodoncia molar",
|
|
100483
|
+
* "appointments": 38,
|
|
100484
|
+
* "lines": 38,
|
|
100485
|
+
* "performed_clp": 9880000
|
|
100486
|
+
* }
|
|
100487
|
+
* ],
|
|
100488
|
+
* "by_category": [
|
|
100489
|
+
* {
|
|
100490
|
+
* "key": "Endodoncia",
|
|
100491
|
+
* "label": "Endodoncia",
|
|
100492
|
+
* "appointments": 52,
|
|
100493
|
+
* "lines": 61,
|
|
100494
|
+
* "performed_clp": 12400000
|
|
100495
|
+
* }
|
|
100496
|
+
* ],
|
|
100497
|
+
* "months": [
|
|
100498
|
+
* {
|
|
100499
|
+
* "month": "2026-09",
|
|
100500
|
+
* "attended": 612,
|
|
100501
|
+
* "performed_clp": 57179516,
|
|
100502
|
+
* "collected_clp": 57172232
|
|
100503
|
+
* }
|
|
100504
|
+
* ]
|
|
98205
100505
|
* }
|
|
98206
100506
|
* }
|
|
98207
100507
|
*/
|
|
98208
100508
|
"application/json": {
|
|
98209
|
-
data
|
|
98210
|
-
meta?: {
|
|
98211
|
-
[key: string]: unknown;
|
|
98212
|
-
};
|
|
100509
|
+
data: components["schemas"]["ClinicProduccionReport"];
|
|
98213
100510
|
};
|
|
98214
100511
|
};
|
|
98215
100512
|
};
|
|
@@ -98269,9 +100566,15 @@ interface paths {
|
|
|
98269
100566
|
};
|
|
98270
100567
|
};
|
|
98271
100568
|
};
|
|
100569
|
+
put?: never;
|
|
100570
|
+
post?: never;
|
|
100571
|
+
delete?: never;
|
|
100572
|
+
options?: never;
|
|
100573
|
+
head?: never;
|
|
100574
|
+
patch?: never;
|
|
98272
100575
|
trace?: never;
|
|
98273
100576
|
};
|
|
98274
|
-
"/clinic/
|
|
100577
|
+
"/clinic/insights/ingresos": {
|
|
98275
100578
|
parameters: {
|
|
98276
100579
|
query?: never;
|
|
98277
100580
|
header?: never;
|
|
@@ -98279,23 +100582,30 @@ interface paths {
|
|
|
98279
100582
|
cookie?: never;
|
|
98280
100583
|
};
|
|
98281
100584
|
/**
|
|
98282
|
-
*
|
|
98283
|
-
* @description
|
|
100585
|
+
* Ingresos: producción, presupuestado and recaudación by day
|
|
100586
|
+
* @description «Ingresos» (D56) for a Dentalink / Medilink clinic (revenue mirror on; otherwise `state: unavailable`). Per day: producción (performed plan lines by fecha de realización), presupuestado (plans issued, header total, evaluación included, as the vendor's panel) and recaudación (live payments by fecha de recepción), each split `nuevos` (the patient's primera visita starts in that month) vs `tratamiento`. `hoy` carries today's three numbers whatever the window. `by_professional`: producción by PERFORMER; presupuestos, aceptación and monto aceptado by the QUOTING professional under Números comerciales' acceptance rule ($0 and evaluación-only presupuestos out); abonado = paid so far on the plans issued in the period; new patients presented / accepted. Default window: the current month to today. With `professional_id` recaudación is `null` (a payment names no professional). Requires `clinic_money:read`. Accepts `from` / `to` (bare `YYYY-MM-DD`, `to` INCLUSIVE), `location_id` and `professional_id`. The default window is the 90 days ending today in the clinic's own zone. A `professional_id` that is not yours is a 404, never an empty report. Also reachable with `clinic_insights:read` — the aggregates-only «Consultor» role (spec #2441 D11) — in addition to the scope named above. A caller WITHOUT the report’s own scope never receives a patient-identifiable row (`inasistencias.citas` and `packs.expiring` come back empty with `aggregate_only: true` and `rows_withheld` naming the field) and reads the minimum-count floor: always the last 3 closed calendar months with no professional or sucursal filter, whatever was asked (`suppression.filters_ignored`); a count or CLP resting on 1–4 cases is `null`; a rate over fewer than 5 cases, or whose numerator is withheld, is `null`; list rows that add up to a shown total get complementary suppression and leave the list (`suppression.withheld_rows`); per-professional/prestación/weekday outcome rows and per-channel confirmation rows carry rates only; producción serves no per-prestación rows (they nest inside the categorías); clinic-wide cash over whole months stays while its slices are floored. `suppression.min_count` is the floor.
|
|
98284
100587
|
*
|
|
98285
|
-
* **Connected apps:**
|
|
100588
|
+
* **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`.
|
|
98286
100589
|
*/
|
|
98287
100590
|
get: {
|
|
98288
100591
|
parameters: {
|
|
98289
|
-
query?:
|
|
98290
|
-
|
|
98291
|
-
|
|
98292
|
-
|
|
100592
|
+
query?: {
|
|
100593
|
+
/** @description First day of the window, inclusive. Defaults to 90 days before `to`. */
|
|
100594
|
+
from?: string;
|
|
100595
|
+
/** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
|
|
100596
|
+
to?: string;
|
|
100597
|
+
/** @description One sucursal. Omit for all of them. */
|
|
100598
|
+
location_id?: string;
|
|
100599
|
+
/** @description One profesional. A foreign id is a 404, never an empty report. */
|
|
100600
|
+
professional_id?: string;
|
|
98293
100601
|
};
|
|
100602
|
+
header?: never;
|
|
100603
|
+
path?: never;
|
|
98294
100604
|
cookie?: never;
|
|
98295
100605
|
};
|
|
98296
100606
|
requestBody?: never;
|
|
98297
100607
|
responses: {
|
|
98298
|
-
/** @description
|
|
100608
|
+
/** @description Clinic Ingresos */
|
|
98299
100609
|
200: {
|
|
98300
100610
|
headers: {
|
|
98301
100611
|
[name: string]: unknown;
|
|
@@ -98304,31 +100614,111 @@ interface paths {
|
|
|
98304
100614
|
/**
|
|
98305
100615
|
* @example {
|
|
98306
100616
|
* "data": {
|
|
98307
|
-
* "
|
|
100617
|
+
* "from": "2026-10-01",
|
|
100618
|
+
* "to": "2026-10-08",
|
|
100619
|
+
* "today": "2026-10-08",
|
|
100620
|
+
* "timezone": "America/Santiago",
|
|
100621
|
+
* "location_id": null,
|
|
100622
|
+
* "professional_id": null,
|
|
100623
|
+
* "state": "ready",
|
|
100624
|
+
* "state_reason": null,
|
|
100625
|
+
* "source": {
|
|
100626
|
+
* "kind": "mirror",
|
|
100627
|
+
* "synced_at": "2026-10-08T20:10:00.000Z"
|
|
100628
|
+
* },
|
|
100629
|
+
* "rules": {
|
|
100630
|
+
* "produccion": "Lo realizado en el box …",
|
|
100631
|
+
* "presupuestado": "Presupuestos creados en el día …",
|
|
100632
|
+
* "recaudacion": "Pagos recibidos en el día …",
|
|
100633
|
+
* "nuevos": "Paciente nuevo: su primera visita es en ese mismo mes …",
|
|
100634
|
+
* "aceptacion": "Aceptados con la misma regla de Números comerciales …",
|
|
100635
|
+
* "abonado": "Lo ya pagado a los presupuestos creados en el período …"
|
|
100636
|
+
* },
|
|
100637
|
+
* "hoy": {
|
|
100638
|
+
* "day": "2026-10-08",
|
|
100639
|
+
* "produccion_clp": 3670982,
|
|
100640
|
+
* "prestaciones": 47,
|
|
100641
|
+
* "presupuestado_clp": 4381028,
|
|
100642
|
+
* "presupuestos": 18,
|
|
100643
|
+
* "recaudado_clp": 3307992,
|
|
100644
|
+
* "pagos": 21
|
|
100645
|
+
* },
|
|
100646
|
+
* "totals": {
|
|
100647
|
+
* "produccion": {
|
|
100648
|
+
* "total_clp": 18626657,
|
|
100649
|
+
* "nuevos_clp": 412000,
|
|
100650
|
+
* "tratamiento_clp": 3258982,
|
|
100651
|
+
* "prestaciones": 47
|
|
100652
|
+
* },
|
|
100653
|
+
* "presupuestado": {
|
|
100654
|
+
* "total_clp": 25014395,
|
|
100655
|
+
* "nuevos_clp": 1072572,
|
|
100656
|
+
* "tratamiento_clp": 3308456,
|
|
100657
|
+
* "presupuestos": 18
|
|
100658
|
+
* },
|
|
100659
|
+
* "recaudacion": {
|
|
100660
|
+
* "total_clp": 14856381,
|
|
100661
|
+
* "nuevos_clp": 811084,
|
|
100662
|
+
* "tratamiento_clp": 2496908,
|
|
100663
|
+
* "pagos": 21
|
|
100664
|
+
* }
|
|
100665
|
+
* },
|
|
100666
|
+
* "days": [
|
|
98308
100667
|
* {
|
|
98309
|
-
* "
|
|
98310
|
-
* "
|
|
98311
|
-
*
|
|
98312
|
-
*
|
|
98313
|
-
*
|
|
98314
|
-
*
|
|
98315
|
-
*
|
|
98316
|
-
* "
|
|
98317
|
-
*
|
|
98318
|
-
*
|
|
98319
|
-
*
|
|
98320
|
-
*
|
|
98321
|
-
*
|
|
100668
|
+
* "day": "2026-10-08",
|
|
100669
|
+
* "produccion": {
|
|
100670
|
+
* "total_clp": 3670982,
|
|
100671
|
+
* "nuevos_clp": 412000,
|
|
100672
|
+
* "tratamiento_clp": 3258982,
|
|
100673
|
+
* "prestaciones": 47
|
|
100674
|
+
* },
|
|
100675
|
+
* "presupuestado": {
|
|
100676
|
+
* "total_clp": 4381028,
|
|
100677
|
+
* "nuevos_clp": 1072572,
|
|
100678
|
+
* "tratamiento_clp": 3308456,
|
|
100679
|
+
* "presupuestos": 18
|
|
100680
|
+
* },
|
|
100681
|
+
* "recaudacion": {
|
|
100682
|
+
* "total_clp": 3307992,
|
|
100683
|
+
* "nuevos_clp": 811084,
|
|
100684
|
+
* "tratamiento_clp": 2496908,
|
|
100685
|
+
* "pagos": 21
|
|
100686
|
+
* }
|
|
100687
|
+
* }
|
|
100688
|
+
* ],
|
|
100689
|
+
* "clinic": {
|
|
100690
|
+
* "produccion_clp": 18626657,
|
|
100691
|
+
* "prestaciones": 52,
|
|
100692
|
+
* "presupuestos": 14,
|
|
100693
|
+
* "presupuestado_clp": 5120000,
|
|
100694
|
+
* "aceptados": 9,
|
|
100695
|
+
* "aceptacion_pct": 64.3,
|
|
100696
|
+
* "aceptado_clp": 3010000,
|
|
100697
|
+
* "abonado_clp": 1240000,
|
|
100698
|
+
* "nuevos_presentados": 5,
|
|
100699
|
+
* "nuevos_aceptados": 3
|
|
100700
|
+
* },
|
|
100701
|
+
* "by_professional": [
|
|
100702
|
+
* {
|
|
100703
|
+
* "professional_id": "6b1f3c2e-8a4d-4f0e-9c1b-2d7e5a9f0c31",
|
|
100704
|
+
* "professional_name": "Ana Rojas",
|
|
100705
|
+
* "produccion_clp": 3685671,
|
|
100706
|
+
* "prestaciones": 52,
|
|
100707
|
+
* "presupuestos": 14,
|
|
100708
|
+
* "presupuestado_clp": 5120000,
|
|
100709
|
+
* "aceptados": 9,
|
|
100710
|
+
* "aceptacion_pct": 64.3,
|
|
100711
|
+
* "aceptado_clp": 3010000,
|
|
100712
|
+
* "abonado_clp": 1240000,
|
|
100713
|
+
* "nuevos_presentados": 5,
|
|
100714
|
+
* "nuevos_aceptados": 3
|
|
98322
100715
|
* }
|
|
98323
100716
|
* ]
|
|
98324
100717
|
* }
|
|
98325
100718
|
* }
|
|
98326
100719
|
*/
|
|
98327
100720
|
"application/json": {
|
|
98328
|
-
data
|
|
98329
|
-
meta?: {
|
|
98330
|
-
[key: string]: unknown;
|
|
98331
|
-
};
|
|
100721
|
+
data: components["schemas"]["ClinicIngresosReport"];
|
|
98332
100722
|
};
|
|
98333
100723
|
};
|
|
98334
100724
|
};
|
|
@@ -98396,7 +100786,7 @@ interface paths {
|
|
|
98396
100786
|
patch?: never;
|
|
98397
100787
|
trace?: never;
|
|
98398
100788
|
};
|
|
98399
|
-
"/clinic/
|
|
100789
|
+
"/clinic/insights/ingresos/months": {
|
|
98400
100790
|
parameters: {
|
|
98401
100791
|
query?: never;
|
|
98402
100792
|
header?: never;
|
|
@@ -98404,23 +100794,25 @@ interface paths {
|
|
|
98404
100794
|
cookie?: never;
|
|
98405
100795
|
};
|
|
98406
100796
|
/**
|
|
98407
|
-
*
|
|
98408
|
-
* @description The
|
|
100797
|
+
* Ingresos: doctor × month comparison
|
|
100798
|
+
* @description The last `months` calendar months (default 6, at most 12, the current one to today): per month the clinic's producción, recaudación, presupuestos, aceptación and monto aceptado; per doctor the same by month (producción by performer, the rest by the quoting professional over the presupuestos issued that month). Requires `clinic_money:read`.
|
|
98409
100799
|
*
|
|
98410
|
-
* **Connected apps:**
|
|
100800
|
+
* **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`.
|
|
98411
100801
|
*/
|
|
98412
100802
|
get: {
|
|
98413
100803
|
parameters: {
|
|
98414
|
-
query?:
|
|
98415
|
-
|
|
98416
|
-
|
|
98417
|
-
|
|
100804
|
+
query?: {
|
|
100805
|
+
/** @description Calendar months to compare, the current one included (default 6). */
|
|
100806
|
+
months?: number;
|
|
100807
|
+
location_id?: string;
|
|
98418
100808
|
};
|
|
100809
|
+
header?: never;
|
|
100810
|
+
path?: never;
|
|
98419
100811
|
cookie?: never;
|
|
98420
100812
|
};
|
|
98421
100813
|
requestBody?: never;
|
|
98422
100814
|
responses: {
|
|
98423
|
-
/** @description
|
|
100815
|
+
/** @description Clinic Ingresos by doctor and month */
|
|
98424
100816
|
200: {
|
|
98425
100817
|
headers: {
|
|
98426
100818
|
[name: string]: unknown;
|
|
@@ -98429,31 +100821,49 @@ interface paths {
|
|
|
98429
100821
|
/**
|
|
98430
100822
|
* @example {
|
|
98431
100823
|
* "data": {
|
|
98432
|
-
* "
|
|
100824
|
+
* "from": "2026-09-01",
|
|
100825
|
+
* "to": "2026-10-08",
|
|
100826
|
+
* "state": "ready",
|
|
100827
|
+
* "rules": {
|
|
100828
|
+
* "produccion": "Lo realizado en el box …",
|
|
100829
|
+
* "presupuestado": "Presupuestos creados en el día …",
|
|
100830
|
+
* "recaudacion": "Pagos recibidos en el día …",
|
|
100831
|
+
* "nuevos": "Paciente nuevo: su primera visita es en ese mismo mes …",
|
|
100832
|
+
* "aceptacion": "Aceptados con la misma regla de Números comerciales …",
|
|
100833
|
+
* "abonado": "Lo ya pagado a los presupuestos creados en el período …"
|
|
100834
|
+
* },
|
|
100835
|
+
* "months": [
|
|
98433
100836
|
* {
|
|
98434
|
-
* "
|
|
98435
|
-
* "
|
|
98436
|
-
* "
|
|
98437
|
-
* "
|
|
98438
|
-
* "
|
|
98439
|
-
* "
|
|
98440
|
-
* "
|
|
98441
|
-
*
|
|
98442
|
-
*
|
|
98443
|
-
*
|
|
98444
|
-
*
|
|
98445
|
-
* "
|
|
98446
|
-
* "
|
|
100837
|
+
* "month": "2026-09",
|
|
100838
|
+
* "produccion_clp": 57179516,
|
|
100839
|
+
* "recaudacion_clp": 57172232,
|
|
100840
|
+
* "presupuestos": 278,
|
|
100841
|
+
* "presupuestado_clp": 112745314,
|
|
100842
|
+
* "aceptacion_pct": 63.1,
|
|
100843
|
+
* "aceptado_clp": 51093178
|
|
100844
|
+
* }
|
|
100845
|
+
* ],
|
|
100846
|
+
* "professionals": [
|
|
100847
|
+
* {
|
|
100848
|
+
* "professional_id": "6b1f3c2e-8a4d-4f0e-9c1b-2d7e5a9f0c31",
|
|
100849
|
+
* "professional_name": "Ana Rojas",
|
|
100850
|
+
* "months": [
|
|
100851
|
+
* {
|
|
100852
|
+
* "month": "2026-09",
|
|
100853
|
+
* "produccion_clp": 9623135,
|
|
100854
|
+
* "presupuestos": 41,
|
|
100855
|
+
* "presupuestado_clp": 18200000,
|
|
100856
|
+
* "aceptacion_pct": 68.3,
|
|
100857
|
+
* "aceptado_clp": 9100000
|
|
100858
|
+
* }
|
|
100859
|
+
* ]
|
|
98447
100860
|
* }
|
|
98448
100861
|
* ]
|
|
98449
100862
|
* }
|
|
98450
100863
|
* }
|
|
98451
100864
|
*/
|
|
98452
100865
|
"application/json": {
|
|
98453
|
-
data
|
|
98454
|
-
meta?: {
|
|
98455
|
-
[key: string]: unknown;
|
|
98456
|
-
};
|
|
100866
|
+
data: components["schemas"]["ClinicIngresosMonths"];
|
|
98457
100867
|
};
|
|
98458
100868
|
};
|
|
98459
100869
|
};
|
|
@@ -98521,41 +100931,31 @@ interface paths {
|
|
|
98521
100931
|
patch?: never;
|
|
98522
100932
|
trace?: never;
|
|
98523
100933
|
};
|
|
98524
|
-
"/clinic/
|
|
100934
|
+
"/clinic/insights/ingresos/days/{day}": {
|
|
98525
100935
|
parameters: {
|
|
98526
100936
|
query?: never;
|
|
98527
100937
|
header?: never;
|
|
98528
100938
|
path?: never;
|
|
98529
100939
|
cookie?: never;
|
|
98530
100940
|
};
|
|
98531
|
-
get?: never;
|
|
98532
|
-
put?: never;
|
|
98533
100941
|
/**
|
|
98534
|
-
*
|
|
98535
|
-
* @description
|
|
100942
|
+
* Ingresos: one day opened (its plans, payments and producción)
|
|
100943
|
+
* @description The plans issued and payments received on one clinic day, each marked `nuevo` / `tratamiento`, plans with the Números comerciales verdict, plus producción per performer. Patient names only for a caller allowed to see identity (`contacts:read` + `clinic:read`, plus `clinic_patients:read` for an API credential); otherwise `patient.name` is `null`. Requires `clinic_money:read`.
|
|
98536
100944
|
*
|
|
98537
|
-
* **Connected apps:**
|
|
100945
|
+
* **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`.
|
|
98538
100946
|
*/
|
|
98539
|
-
|
|
100947
|
+
get: {
|
|
98540
100948
|
parameters: {
|
|
98541
100949
|
query?: never;
|
|
98542
|
-
header?:
|
|
98543
|
-
/** @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. */
|
|
98544
|
-
"Idempotency-Key"?: string;
|
|
98545
|
-
};
|
|
100950
|
+
header?: never;
|
|
98546
100951
|
path: {
|
|
98547
|
-
|
|
100952
|
+
day: string;
|
|
98548
100953
|
};
|
|
98549
100954
|
cookie?: never;
|
|
98550
100955
|
};
|
|
98551
|
-
requestBody?:
|
|
98552
|
-
content: {
|
|
98553
|
-
/** @example {} */
|
|
98554
|
-
"application/json": Record<string, never>;
|
|
98555
|
-
};
|
|
98556
|
-
};
|
|
100956
|
+
requestBody?: never;
|
|
98557
100957
|
responses: {
|
|
98558
|
-
/** @description
|
|
100958
|
+
/** @description One clinic day of Ingresos */
|
|
98559
100959
|
200: {
|
|
98560
100960
|
headers: {
|
|
98561
100961
|
[name: string]: unknown;
|
|
@@ -98564,28 +100964,49 @@ interface paths {
|
|
|
98564
100964
|
/**
|
|
98565
100965
|
* @example {
|
|
98566
100966
|
* "data": {
|
|
98567
|
-
* "
|
|
98568
|
-
* "
|
|
98569
|
-
* "
|
|
98570
|
-
*
|
|
98571
|
-
*
|
|
98572
|
-
*
|
|
98573
|
-
*
|
|
98574
|
-
*
|
|
98575
|
-
*
|
|
98576
|
-
*
|
|
98577
|
-
*
|
|
98578
|
-
*
|
|
98579
|
-
*
|
|
98580
|
-
*
|
|
100967
|
+
* "day": "2026-10-08",
|
|
100968
|
+
* "identity": true,
|
|
100969
|
+
* "plans": [
|
|
100970
|
+
* {
|
|
100971
|
+
* "plan_id": "1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
|
|
100972
|
+
* "patient": {
|
|
100973
|
+
* "id": "7e6d5c4b-3a29-4180-9f8e-7d6c5b4a3928",
|
|
100974
|
+
* "name": "Paciente de ejemplo"
|
|
100975
|
+
* },
|
|
100976
|
+
* "professional_id": "6b1f3c2e-8a4d-4f0e-9c1b-2d7e5a9f0c31",
|
|
100977
|
+
* "professional_name": "Ana Rojas",
|
|
100978
|
+
* "total_clp": 640000,
|
|
100979
|
+
* "abonado_clp": 120000,
|
|
100980
|
+
* "deuda_clp": 520000,
|
|
100981
|
+
* "tipo": "nuevo",
|
|
100982
|
+
* "aceptado": true
|
|
100983
|
+
* }
|
|
100984
|
+
* ],
|
|
100985
|
+
* "payments": [
|
|
100986
|
+
* {
|
|
100987
|
+
* "payment_id": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
|
|
100988
|
+
* "time": "11:42",
|
|
100989
|
+
* "patient": {
|
|
100990
|
+
* "id": "7e6d5c4b-3a29-4180-9f8e-7d6c5b4a3928",
|
|
100991
|
+
* "name": "Paciente de ejemplo"
|
|
100992
|
+
* },
|
|
100993
|
+
* "amount_clp": 120000,
|
|
100994
|
+
* "tipo": "nuevo"
|
|
100995
|
+
* }
|
|
100996
|
+
* ],
|
|
100997
|
+
* "produccion": [
|
|
100998
|
+
* {
|
|
100999
|
+
* "professional_id": "6b1f3c2e-8a4d-4f0e-9c1b-2d7e5a9f0c31",
|
|
101000
|
+
* "professional_name": "Ana Rojas",
|
|
101001
|
+
* "prestaciones": 9,
|
|
101002
|
+
* "produccion_clp": 812000
|
|
101003
|
+
* }
|
|
101004
|
+
* ]
|
|
98581
101005
|
* }
|
|
98582
101006
|
* }
|
|
98583
101007
|
*/
|
|
98584
101008
|
"application/json": {
|
|
98585
|
-
data
|
|
98586
|
-
meta?: {
|
|
98587
|
-
[key: string]: unknown;
|
|
98588
|
-
};
|
|
101009
|
+
data: components["schemas"]["ClinicIngresosDay"];
|
|
98589
101010
|
};
|
|
98590
101011
|
};
|
|
98591
101012
|
};
|
|
@@ -98645,6 +101066,8 @@ interface paths {
|
|
|
98645
101066
|
};
|
|
98646
101067
|
};
|
|
98647
101068
|
};
|
|
101069
|
+
put?: never;
|
|
101070
|
+
post?: never;
|
|
98648
101071
|
delete?: never;
|
|
98649
101072
|
options?: never;
|
|
98650
101073
|
head?: never;
|
|
@@ -99366,7 +101789,7 @@ interface paths {
|
|
|
99366
101789
|
};
|
|
99367
101790
|
/**
|
|
99368
101791
|
* The month's Meta mensual and its progress
|
|
99369
|
-
* @description Requires `clinic_money:read`. The owner's three targets for the month (primeras visitas booked, cierres, cobrado in CLP; `null` = not set) with what has been achieved so far: primeras visitas = citas created in the month whose Tipo de agendamiento is Nuevo or Nuevo · reagenda; cierres as Números comerciales counts them; cobrado = payments received. For the current month, `pace` carries the ritmo diario. The ritmo diario is a catch-up pace: (meta − achieved before today) ÷ working days left, today included. Working days come from the clinic's opening hours and holidays, in the clinic's timezone. A figure with no target has a count and no pace. This is not the Ads goal, which is marketing's own.
|
|
101792
|
+
* @description Requires `clinic_money:read`. The owner's three targets for the month (primeras visitas booked, cierres, cobrado in CLP; `null` = not set) with what has been achieved so far: primeras visitas = citas created in the month whose Tipo de agendamiento is Nuevo or Nuevo · reagenda; cierres as Números comerciales counts them; cobrado = payments received. For the current month, `pace` carries the ritmo diario. The ritmo diario is a catch-up pace: (meta − achieved before today) ÷ working days left, today included, each day weighed by its opening hours against the clinic's longest day (a 9–14 Saturday next to 9–19 weekdays weighs 0.5), times today's weight (`per_day`). Working days come from the clinic's opening hours and holidays, in the clinic's timezone. A figure with no target has a count and no pace. This is not the Ads goal, which is marketing's own.
|
|
99370
101793
|
*
|
|
99371
101794
|
* **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`.
|
|
99372
101795
|
*/
|
|
@@ -99409,6 +101832,20 @@ interface paths {
|
|
|
99409
101832
|
* "total": 21,
|
|
99410
101833
|
* "left": 10
|
|
99411
101834
|
* },
|
|
101835
|
+
* "history": [
|
|
101836
|
+
* {
|
|
101837
|
+
* "date": "2026-10-01",
|
|
101838
|
+
* "booked": 108,
|
|
101839
|
+
* "primeras_visitas": 26,
|
|
101840
|
+
* "plata_clp": 1251950
|
|
101841
|
+
* },
|
|
101842
|
+
* {
|
|
101843
|
+
* "date": "2026-10-02",
|
|
101844
|
+
* "booked": 49,
|
|
101845
|
+
* "primeras_visitas": 11,
|
|
101846
|
+
* "plata_clp": 359086
|
|
101847
|
+
* }
|
|
101848
|
+
* ],
|
|
99412
101849
|
* "pace": {
|
|
99413
101850
|
* "primeras_visitas": {
|
|
99414
101851
|
* "status": "open",
|
|
@@ -99416,6 +101853,8 @@ interface paths {
|
|
|
99416
101853
|
* "achieved_before_today": 18,
|
|
99417
101854
|
* "remaining": 22,
|
|
99418
101855
|
* "working_days_left": 10,
|
|
101856
|
+
* "weighted_days_left": 9.5,
|
|
101857
|
+
* "day_weight": 1,
|
|
99419
101858
|
* "per_day": 3
|
|
99420
101859
|
* },
|
|
99421
101860
|
* "cierres": null,
|
|
@@ -99425,7 +101864,9 @@ interface paths {
|
|
|
99425
101864
|
* "achieved_before_today": 7450000,
|
|
99426
101865
|
* "remaining": 10550000,
|
|
99427
101866
|
* "working_days_left": 10,
|
|
99428
|
-
* "
|
|
101867
|
+
* "weighted_days_left": 9.5,
|
|
101868
|
+
* "day_weight": 1,
|
|
101869
|
+
* "per_day": 1110527
|
|
99429
101870
|
* }
|
|
99430
101871
|
* }
|
|
99431
101872
|
* }
|
|
@@ -99452,6 +101893,12 @@ interface paths {
|
|
|
99452
101893
|
total: number;
|
|
99453
101894
|
left: number;
|
|
99454
101895
|
};
|
|
101896
|
+
history: {
|
|
101897
|
+
date: string;
|
|
101898
|
+
booked: number;
|
|
101899
|
+
primeras_visitas: number;
|
|
101900
|
+
plata_clp: number | null;
|
|
101901
|
+
}[];
|
|
99455
101902
|
pace: {
|
|
99456
101903
|
primeras_visitas: {
|
|
99457
101904
|
/** @enum {string} */
|
|
@@ -99460,6 +101907,8 @@ interface paths {
|
|
|
99460
101907
|
achieved_before_today: number;
|
|
99461
101908
|
remaining: number;
|
|
99462
101909
|
working_days_left: number;
|
|
101910
|
+
weighted_days_left: number;
|
|
101911
|
+
day_weight: number;
|
|
99463
101912
|
per_day: number | null;
|
|
99464
101913
|
} | null;
|
|
99465
101914
|
cierres: {
|
|
@@ -99469,6 +101918,8 @@ interface paths {
|
|
|
99469
101918
|
achieved_before_today: number;
|
|
99470
101919
|
remaining: number;
|
|
99471
101920
|
working_days_left: number;
|
|
101921
|
+
weighted_days_left: number;
|
|
101922
|
+
day_weight: number;
|
|
99472
101923
|
per_day: number | null;
|
|
99473
101924
|
} | null;
|
|
99474
101925
|
cobrado_clp: {
|
|
@@ -99478,6 +101929,8 @@ interface paths {
|
|
|
99478
101929
|
achieved_before_today: number;
|
|
99479
101930
|
remaining: number;
|
|
99480
101931
|
working_days_left: number;
|
|
101932
|
+
weighted_days_left: number;
|
|
101933
|
+
day_weight: number;
|
|
99481
101934
|
per_day: number | null;
|
|
99482
101935
|
} | null;
|
|
99483
101936
|
} | null;
|
|
@@ -99601,6 +102054,20 @@ interface paths {
|
|
|
99601
102054
|
* "total": 21,
|
|
99602
102055
|
* "left": 10
|
|
99603
102056
|
* },
|
|
102057
|
+
* "history": [
|
|
102058
|
+
* {
|
|
102059
|
+
* "date": "2026-10-01",
|
|
102060
|
+
* "booked": 108,
|
|
102061
|
+
* "primeras_visitas": 26,
|
|
102062
|
+
* "plata_clp": 1251950
|
|
102063
|
+
* },
|
|
102064
|
+
* {
|
|
102065
|
+
* "date": "2026-10-02",
|
|
102066
|
+
* "booked": 49,
|
|
102067
|
+
* "primeras_visitas": 11,
|
|
102068
|
+
* "plata_clp": 359086
|
|
102069
|
+
* }
|
|
102070
|
+
* ],
|
|
99604
102071
|
* "pace": {
|
|
99605
102072
|
* "primeras_visitas": {
|
|
99606
102073
|
* "status": "open",
|
|
@@ -99608,6 +102075,8 @@ interface paths {
|
|
|
99608
102075
|
* "achieved_before_today": 18,
|
|
99609
102076
|
* "remaining": 22,
|
|
99610
102077
|
* "working_days_left": 10,
|
|
102078
|
+
* "weighted_days_left": 9.5,
|
|
102079
|
+
* "day_weight": 1,
|
|
99611
102080
|
* "per_day": 3
|
|
99612
102081
|
* },
|
|
99613
102082
|
* "cierres": null,
|
|
@@ -99617,7 +102086,9 @@ interface paths {
|
|
|
99617
102086
|
* "achieved_before_today": 7450000,
|
|
99618
102087
|
* "remaining": 10550000,
|
|
99619
102088
|
* "working_days_left": 10,
|
|
99620
|
-
* "
|
|
102089
|
+
* "weighted_days_left": 9.5,
|
|
102090
|
+
* "day_weight": 1,
|
|
102091
|
+
* "per_day": 1110527
|
|
99621
102092
|
* }
|
|
99622
102093
|
* }
|
|
99623
102094
|
* }
|
|
@@ -99644,6 +102115,12 @@ interface paths {
|
|
|
99644
102115
|
total: number;
|
|
99645
102116
|
left: number;
|
|
99646
102117
|
};
|
|
102118
|
+
history: {
|
|
102119
|
+
date: string;
|
|
102120
|
+
booked: number;
|
|
102121
|
+
primeras_visitas: number;
|
|
102122
|
+
plata_clp: number | null;
|
|
102123
|
+
}[];
|
|
99647
102124
|
pace: {
|
|
99648
102125
|
primeras_visitas: {
|
|
99649
102126
|
/** @enum {string} */
|
|
@@ -99652,6 +102129,8 @@ interface paths {
|
|
|
99652
102129
|
achieved_before_today: number;
|
|
99653
102130
|
remaining: number;
|
|
99654
102131
|
working_days_left: number;
|
|
102132
|
+
weighted_days_left: number;
|
|
102133
|
+
day_weight: number;
|
|
99655
102134
|
per_day: number | null;
|
|
99656
102135
|
} | null;
|
|
99657
102136
|
cierres: {
|
|
@@ -99661,6 +102140,8 @@ interface paths {
|
|
|
99661
102140
|
achieved_before_today: number;
|
|
99662
102141
|
remaining: number;
|
|
99663
102142
|
working_days_left: number;
|
|
102143
|
+
weighted_days_left: number;
|
|
102144
|
+
day_weight: number;
|
|
99664
102145
|
per_day: number | null;
|
|
99665
102146
|
} | null;
|
|
99666
102147
|
cobrado_clp: {
|
|
@@ -99670,6 +102151,8 @@ interface paths {
|
|
|
99670
102151
|
achieved_before_today: number;
|
|
99671
102152
|
remaining: number;
|
|
99672
102153
|
working_days_left: number;
|
|
102154
|
+
weighted_days_left: number;
|
|
102155
|
+
day_weight: number;
|
|
99673
102156
|
per_day: number | null;
|
|
99674
102157
|
} | null;
|
|
99675
102158
|
} | null;
|
|
@@ -99749,7 +102232,7 @@ interface paths {
|
|
|
99749
102232
|
};
|
|
99750
102233
|
/**
|
|
99751
102234
|
* The «Hoy» strip: is today on track?
|
|
99752
|
-
* @description Requires `clinic:read` or `clinic_money:read`; cobrado figures need `clinic_money:read` and are `null` without it. Bookings made today (citas created today, for any date) with their Tipo de agendamiento
|
|
102235
|
+
* @description Requires `clinic:read` or `clinic_money:read`; cobrado figures need `clinic_money:read` and are `null` without it. Bookings made today (citas created today, for any date; an anulación is not a booking; a moved cita stays a booking of the day it was made, and its replacement counts on the day it is re-booked) with their Tipo de agendamiento judged at the moment of booking, the bookings of the last hour, the same counts for the previous working day, cobrado today and the part from new patients (patients with a primera visita this month; `null` when the clinic's vendor has no payment mirror, e.g. Reservo), and the paces of today's month. The ritmo diario is a catch-up pace: (meta − achieved before today) ÷ working days left, today included, each day weighed by its opening hours against the clinic's longest day (a 9–14 Saturday next to 9–19 weekdays weighs 0.5), times today's weight (`per_day`). Working days come from the clinic's opening hours and holidays, in the clinic's timezone. A figure with no target has a count and no pace. The pace of cobrado is the Meta mensual's, set against the clinic's total cobrado.
|
|
99753
102236
|
*
|
|
99754
102237
|
* **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`.
|
|
99755
102238
|
*/
|
|
@@ -99789,6 +102272,32 @@ interface paths {
|
|
|
99789
102272
|
* "total": 2,
|
|
99790
102273
|
* "primeras_visitas": 1
|
|
99791
102274
|
* },
|
|
102275
|
+
* "by_hour": [
|
|
102276
|
+
* {
|
|
102277
|
+
* "hour": 9,
|
|
102278
|
+
* "total": 3,
|
|
102279
|
+
* "primeras_visitas": 1
|
|
102280
|
+
* },
|
|
102281
|
+
* {
|
|
102282
|
+
* "hour": 11,
|
|
102283
|
+
* "total": 4,
|
|
102284
|
+
* "primeras_visitas": 2
|
|
102285
|
+
* },
|
|
102286
|
+
* {
|
|
102287
|
+
* "hour": 14,
|
|
102288
|
+
* "total": 2,
|
|
102289
|
+
* "primeras_visitas": 1
|
|
102290
|
+
* }
|
|
102291
|
+
* ],
|
|
102292
|
+
* "origin": {
|
|
102293
|
+
* "meta": 2,
|
|
102294
|
+
* "organic": 1,
|
|
102295
|
+
* "unknown": 1
|
|
102296
|
+
* },
|
|
102297
|
+
* "from_whatsapp": {
|
|
102298
|
+
* "total": 3,
|
|
102299
|
+
* "primeras_visitas": 2
|
|
102300
|
+
* },
|
|
99792
102301
|
* "cobrado_clp": 640000,
|
|
99793
102302
|
* "cobrado_new_patients_clp": 90000
|
|
99794
102303
|
* },
|
|
@@ -99815,6 +102324,8 @@ interface paths {
|
|
|
99815
102324
|
* "achieved_before_today": 18,
|
|
99816
102325
|
* "remaining": 22,
|
|
99817
102326
|
* "working_days_left": 10,
|
|
102327
|
+
* "weighted_days_left": 9.5,
|
|
102328
|
+
* "day_weight": 1,
|
|
99818
102329
|
* "per_day": 3
|
|
99819
102330
|
* },
|
|
99820
102331
|
* "cobrado_clp": null
|
|
@@ -99844,6 +102355,20 @@ interface paths {
|
|
|
99844
102355
|
total: number;
|
|
99845
102356
|
primeras_visitas: number;
|
|
99846
102357
|
};
|
|
102358
|
+
by_hour: {
|
|
102359
|
+
hour: number;
|
|
102360
|
+
total: number;
|
|
102361
|
+
primeras_visitas: number;
|
|
102362
|
+
}[];
|
|
102363
|
+
origin: {
|
|
102364
|
+
meta: number;
|
|
102365
|
+
organic: number;
|
|
102366
|
+
unknown: number;
|
|
102367
|
+
};
|
|
102368
|
+
from_whatsapp: {
|
|
102369
|
+
total: number;
|
|
102370
|
+
primeras_visitas: number;
|
|
102371
|
+
};
|
|
99847
102372
|
};
|
|
99848
102373
|
previous_working_day: {
|
|
99849
102374
|
date: string;
|
|
@@ -99869,6 +102394,8 @@ interface paths {
|
|
|
99869
102394
|
achieved_before_today: number;
|
|
99870
102395
|
remaining: number;
|
|
99871
102396
|
working_days_left: number;
|
|
102397
|
+
weighted_days_left: number;
|
|
102398
|
+
day_weight: number;
|
|
99872
102399
|
per_day: number | null;
|
|
99873
102400
|
} | null;
|
|
99874
102401
|
cobrado_clp: {
|
|
@@ -99878,6 +102405,8 @@ interface paths {
|
|
|
99878
102405
|
achieved_before_today: number;
|
|
99879
102406
|
remaining: number;
|
|
99880
102407
|
working_days_left: number;
|
|
102408
|
+
weighted_days_left: number;
|
|
102409
|
+
day_weight: number;
|
|
99881
102410
|
per_day: number | null;
|
|
99882
102411
|
} | null;
|
|
99883
102412
|
};
|
|
@@ -99949,6 +102478,172 @@ interface paths {
|
|
|
99949
102478
|
patch?: never;
|
|
99950
102479
|
trace?: never;
|
|
99951
102480
|
};
|
|
102481
|
+
"/clinic/today/bookings": {
|
|
102482
|
+
parameters: {
|
|
102483
|
+
query?: never;
|
|
102484
|
+
header?: never;
|
|
102485
|
+
path?: never;
|
|
102486
|
+
cookie?: never;
|
|
102487
|
+
};
|
|
102488
|
+
/**
|
|
102489
|
+
* The citas behind the «Hoy» numbers
|
|
102490
|
+
* @description Requires `clinic:read`. The citas booked on one clinic day (`date`, default today; never a future day): when they were booked (the vendor's own creation time when the mirror carries it — Reservo — else when Vitrina first saw the cita, which is every Dentalink / Medilink cita), the hour of that in the clinic's clock, who the patient is, for when, with which professional, the Tipo de agendamiento judged as of the booking day, the Origen, whether the patient's linked contact had WhatsApp activity from two days before the booking day («Desde WhatsApp»), and the patient's last attended visit before that day. An anulación is not a booking; a moved cita («Cambio de fecha») stays a booking of the day it was made.
|
|
102491
|
+
*
|
|
102492
|
+
* **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`.
|
|
102493
|
+
*/
|
|
102494
|
+
get: {
|
|
102495
|
+
parameters: {
|
|
102496
|
+
query?: {
|
|
102497
|
+
date?: string;
|
|
102498
|
+
};
|
|
102499
|
+
header?: never;
|
|
102500
|
+
path?: never;
|
|
102501
|
+
cookie?: never;
|
|
102502
|
+
};
|
|
102503
|
+
requestBody?: never;
|
|
102504
|
+
responses: {
|
|
102505
|
+
/** @description The day's bookings, in booking order */
|
|
102506
|
+
200: {
|
|
102507
|
+
headers: {
|
|
102508
|
+
[name: string]: unknown;
|
|
102509
|
+
};
|
|
102510
|
+
content: {
|
|
102511
|
+
/**
|
|
102512
|
+
* @example {
|
|
102513
|
+
* "data": {
|
|
102514
|
+
* "date": "2026-10-13",
|
|
102515
|
+
* "timezone": "America/Santiago",
|
|
102516
|
+
* "rows": [
|
|
102517
|
+
* {
|
|
102518
|
+
* "appointment_id": "6f1c2c1e-1d2b-4c9a-9f3e-0a1b2c3d4e5f",
|
|
102519
|
+
* "booked_at": "2026-10-13T14:12:00.000Z",
|
|
102520
|
+
* "hour": 11,
|
|
102521
|
+
* "starts_at": "2026-10-20T13:00:00.000Z",
|
|
102522
|
+
* "patient": {
|
|
102523
|
+
* "id": "0d9e8f7a-6b5c-4d3e-2f1a-0b9c8d7e6f5a",
|
|
102524
|
+
* "name": "Paciente Ejemplo"
|
|
102525
|
+
* },
|
|
102526
|
+
* "professional_name": "Dra. Ejemplo",
|
|
102527
|
+
* "kind": "new",
|
|
102528
|
+
* "origin": null,
|
|
102529
|
+
* "from_whatsapp": true,
|
|
102530
|
+
* "last_visit": null
|
|
102531
|
+
* }
|
|
102532
|
+
* ]
|
|
102533
|
+
* }
|
|
102534
|
+
* }
|
|
102535
|
+
*/
|
|
102536
|
+
"application/json": {
|
|
102537
|
+
data: {
|
|
102538
|
+
date: string;
|
|
102539
|
+
timezone: string;
|
|
102540
|
+
rows: {
|
|
102541
|
+
/** Format: uuid */
|
|
102542
|
+
appointment_id: string;
|
|
102543
|
+
booked_at: string;
|
|
102544
|
+
hour: number;
|
|
102545
|
+
starts_at: string;
|
|
102546
|
+
patient: {
|
|
102547
|
+
/** Format: uuid */
|
|
102548
|
+
id: string;
|
|
102549
|
+
name: string | null;
|
|
102550
|
+
} | null;
|
|
102551
|
+
professional_name: string | null;
|
|
102552
|
+
/** @enum {string|null} */
|
|
102553
|
+
kind: "new" | "new_rebooked" | "in_treatment" | null;
|
|
102554
|
+
/** @description Origen: the attribution Vitrina Ads reports (people from ads), asked of one person. A person with a linked contact and no ad touch is `organic`; one with no linked contact is `unknown`. Read-only. */
|
|
102555
|
+
origin: {
|
|
102556
|
+
/**
|
|
102557
|
+
* @description `meta`: came from a Meta ad. `organic`: a linked contact with no ad touch. `unknown` («Sin dato»): no contact is linked to the person, so no ad touch can be read.
|
|
102558
|
+
* @enum {string}
|
|
102559
|
+
*/
|
|
102560
|
+
kind: "meta" | "organic" | "unknown";
|
|
102561
|
+
/** @description «Meta · Implantes octubre», «Meta» (ad name unknown), «Orgánico». */
|
|
102562
|
+
label: string;
|
|
102563
|
+
/** @description Meta only: the platform ad id (what `origin_ad_id` takes). */
|
|
102564
|
+
ad_id: string | null;
|
|
102565
|
+
ad_name: string | null;
|
|
102566
|
+
ad_set_name: string | null;
|
|
102567
|
+
campaign_name: string | null;
|
|
102568
|
+
/** @description Meta only: when they first wrote through the ad (or came back). */
|
|
102569
|
+
first_touch_at: string | null;
|
|
102570
|
+
/**
|
|
102571
|
+
* @description `first_message`: the first thing they wrote came from the ad. `returned`: they were already writing and came back through one. Both count as people from ads.
|
|
102572
|
+
* @enum {string|null}
|
|
102573
|
+
*/
|
|
102574
|
+
via: "first_message" | "returned" | null;
|
|
102575
|
+
} | null;
|
|
102576
|
+
from_whatsapp: boolean;
|
|
102577
|
+
last_visit: string | null;
|
|
102578
|
+
}[];
|
|
102579
|
+
};
|
|
102580
|
+
};
|
|
102581
|
+
};
|
|
102582
|
+
};
|
|
102583
|
+
/** @description Validation error */
|
|
102584
|
+
400: {
|
|
102585
|
+
headers: {
|
|
102586
|
+
[name: string]: unknown;
|
|
102587
|
+
};
|
|
102588
|
+
content: {
|
|
102589
|
+
"application/json": components["schemas"]["Error"];
|
|
102590
|
+
};
|
|
102591
|
+
};
|
|
102592
|
+
/** @description Unauthorized */
|
|
102593
|
+
401: {
|
|
102594
|
+
headers: {
|
|
102595
|
+
[name: string]: unknown;
|
|
102596
|
+
};
|
|
102597
|
+
content: {
|
|
102598
|
+
"application/json": components["schemas"]["Error"];
|
|
102599
|
+
};
|
|
102600
|
+
};
|
|
102601
|
+
/** @description Forbidden */
|
|
102602
|
+
403: {
|
|
102603
|
+
headers: {
|
|
102604
|
+
[name: string]: unknown;
|
|
102605
|
+
};
|
|
102606
|
+
content: {
|
|
102607
|
+
"application/json": components["schemas"]["Error"];
|
|
102608
|
+
};
|
|
102609
|
+
};
|
|
102610
|
+
/** @description Not found */
|
|
102611
|
+
404: {
|
|
102612
|
+
headers: {
|
|
102613
|
+
[name: string]: unknown;
|
|
102614
|
+
};
|
|
102615
|
+
content: {
|
|
102616
|
+
"application/json": components["schemas"]["Error"];
|
|
102617
|
+
};
|
|
102618
|
+
};
|
|
102619
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
102620
|
+
409: {
|
|
102621
|
+
headers: {
|
|
102622
|
+
[name: string]: unknown;
|
|
102623
|
+
};
|
|
102624
|
+
content: {
|
|
102625
|
+
"application/json": components["schemas"]["Error"];
|
|
102626
|
+
};
|
|
102627
|
+
};
|
|
102628
|
+
/** @description Rate limited */
|
|
102629
|
+
429: {
|
|
102630
|
+
headers: {
|
|
102631
|
+
[name: string]: unknown;
|
|
102632
|
+
};
|
|
102633
|
+
content: {
|
|
102634
|
+
"application/json": components["schemas"]["Error"];
|
|
102635
|
+
};
|
|
102636
|
+
};
|
|
102637
|
+
};
|
|
102638
|
+
};
|
|
102639
|
+
put?: never;
|
|
102640
|
+
post?: never;
|
|
102641
|
+
delete?: never;
|
|
102642
|
+
options?: never;
|
|
102643
|
+
head?: never;
|
|
102644
|
+
patch?: never;
|
|
102645
|
+
trace?: never;
|
|
102646
|
+
};
|
|
99952
102647
|
"/ads/state": {
|
|
99953
102648
|
parameters: {
|
|
99954
102649
|
query?: never;
|
|
@@ -115848,7 +118543,7 @@ interface paths {
|
|
|
115848
118543
|
};
|
|
115849
118544
|
/**
|
|
115850
118545
|
* Inspect the exact state the AI agent would receive
|
|
115851
|
-
* @description Rebuilds, through the same assembler the worker uses, everything the agent sees on this conversation: the full system prompt, the gated tool catalogue, message history, temperature and step budget. The model and reasoning effort are platform-managed and not included. Read-only — no enrichment, no tool side effects. Answers a
|
|
118546
|
+
* @description Rebuilds, through the same assembler the worker uses, everything the agent sees on this conversation: the full system prompt, the gated tool catalogue, message history, temperature and step budget. The model and reasoning effort are platform-managed and not included. Read-only — no enrichment, no tool side effects. Answers a JSON **file download** (`Content-Disposition: attachment`), not the `{ data }` envelope the other reads use. On a clinic, a connected app reads the patient in the prompt, history and tool results as a pseudonym unless the clinic allows patient names, like every other read.
|
|
115852
118547
|
*/
|
|
115853
118548
|
get: {
|
|
115854
118549
|
parameters: {
|
|
@@ -173447,6 +176142,277 @@ interface components {
|
|
|
173447
176142
|
}[];
|
|
173448
176143
|
}[];
|
|
173449
176144
|
};
|
|
176145
|
+
ClinicProduccionReport: {
|
|
176146
|
+
from: string;
|
|
176147
|
+
to: string;
|
|
176148
|
+
/** Format: uuid */
|
|
176149
|
+
location_id: string | null;
|
|
176150
|
+
/** Format: uuid */
|
|
176151
|
+
professional_id: string | null;
|
|
176152
|
+
/**
|
|
176153
|
+
* @description Which arm produced the money. `mirror_lines`: a Dentalink / Medilink clinic — the vendor's plan lines marked realizado, by fecha de realización, at the line's total (exact). `service_lines`: the cita's frozen Vitrina lines (a native clinic). `catalog_price`: the catálogo's current price for the prestación a mirrored cita names (an estimate). `mixed`: both. `none`: nothing priced anything.
|
|
176154
|
+
* @enum {string}
|
|
176155
|
+
*/
|
|
176156
|
+
basis: "service_lines" | "catalog_price" | "mixed" | "none" | "mirror_lines";
|
|
176157
|
+
totals: {
|
|
176158
|
+
/** @description Attended citas in the window. `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176159
|
+
attended: number | null;
|
|
176160
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176161
|
+
lines: number | null;
|
|
176162
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176163
|
+
lines_without_price: number | null;
|
|
176164
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176165
|
+
performed_clp: number | null;
|
|
176166
|
+
/** @description `payment_allocation.appointment`: money the ledger allocated to these citas. `mirror_payment.received`: every live payment received in the window, by fecha de recepción; `null` with a professional filter (a payment names no professional). */
|
|
176167
|
+
collected_clp: number | null;
|
|
176168
|
+
/** @enum {string} */
|
|
176169
|
+
collected_basis: "payment_allocation.appointment" | "mirror_payment.received";
|
|
176170
|
+
};
|
|
176171
|
+
/** @description Per professional who PERFORMED the work (not who quoted the plan), most CLP first. */
|
|
176172
|
+
by_professional: {
|
|
176173
|
+
/** @description The professional / prestación id, or the categoría text; `__none__` when the line names none. */
|
|
176174
|
+
key: string;
|
|
176175
|
+
label: string | null;
|
|
176176
|
+
/** @description Citas that produced (`mirror_lines`: visits, patient × day). `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176177
|
+
appointments: number | null;
|
|
176178
|
+
/** @description Prestaciones performed. `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176179
|
+
lines: number | null;
|
|
176180
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176181
|
+
performed_clp: number | null;
|
|
176182
|
+
}[];
|
|
176183
|
+
by_service: {
|
|
176184
|
+
/** @description The professional / prestación id, or the categoría text; `__none__` when the line names none. */
|
|
176185
|
+
key: string;
|
|
176186
|
+
label: string | null;
|
|
176187
|
+
/** @description Citas that produced (`mirror_lines`: visits, patient × day). `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176188
|
+
appointments: number | null;
|
|
176189
|
+
/** @description Prestaciones performed. `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176190
|
+
lines: number | null;
|
|
176191
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176192
|
+
performed_clp: number | null;
|
|
176193
|
+
}[];
|
|
176194
|
+
/** @description `clinic_service.categoria` is free text: the label is the key. */
|
|
176195
|
+
by_category: {
|
|
176196
|
+
/** @description The professional / prestación id, or the categoría text; `__none__` when the line names none. */
|
|
176197
|
+
key: string;
|
|
176198
|
+
label: string | null;
|
|
176199
|
+
/** @description Citas that produced (`mirror_lines`: visits, patient × day). `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176200
|
+
appointments: number | null;
|
|
176201
|
+
/** @description Prestaciones performed. `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176202
|
+
lines: number | null;
|
|
176203
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176204
|
+
performed_clp: number | null;
|
|
176205
|
+
}[];
|
|
176206
|
+
months: {
|
|
176207
|
+
/** @description `YYYY-MM`. */
|
|
176208
|
+
month: string;
|
|
176209
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176210
|
+
attended: number | null;
|
|
176211
|
+
/** @description `null` only for a caller without `clinic_money:read`, when it rests on 1–4 cases. */
|
|
176212
|
+
performed_clp: number | null;
|
|
176213
|
+
collected_clp: number | null;
|
|
176214
|
+
}[];
|
|
176215
|
+
/** @description Present only for a caller without `clinic_money:read`. */
|
|
176216
|
+
suppression?: {
|
|
176217
|
+
min_count: number;
|
|
176218
|
+
filters_ignored: boolean;
|
|
176219
|
+
withheld_rows: {
|
|
176220
|
+
[key: string]: number;
|
|
176221
|
+
};
|
|
176222
|
+
};
|
|
176223
|
+
};
|
|
176224
|
+
ClinicIngresosReport: {
|
|
176225
|
+
from: string;
|
|
176226
|
+
to: string;
|
|
176227
|
+
today: string;
|
|
176228
|
+
timezone: string;
|
|
176229
|
+
/** Format: uuid */
|
|
176230
|
+
location_id: string | null;
|
|
176231
|
+
/** Format: uuid */
|
|
176232
|
+
professional_id: string | null;
|
|
176233
|
+
/** @enum {string} */
|
|
176234
|
+
state: "ready" | "unavailable";
|
|
176235
|
+
state_reason: string | null;
|
|
176236
|
+
source: {
|
|
176237
|
+
/** @enum {string} */
|
|
176238
|
+
kind: "mirror" | "none";
|
|
176239
|
+
synced_at: string | null;
|
|
176240
|
+
};
|
|
176241
|
+
rules: {
|
|
176242
|
+
[key: string]: string;
|
|
176243
|
+
};
|
|
176244
|
+
hoy: {
|
|
176245
|
+
day: string;
|
|
176246
|
+
produccion_clp: number;
|
|
176247
|
+
prestaciones: number;
|
|
176248
|
+
presupuestado_clp: number;
|
|
176249
|
+
presupuestos: number;
|
|
176250
|
+
recaudado_clp: number | null;
|
|
176251
|
+
pagos: number | null;
|
|
176252
|
+
};
|
|
176253
|
+
totals: {
|
|
176254
|
+
produccion: {
|
|
176255
|
+
total_clp: number;
|
|
176256
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176257
|
+
nuevos_clp: number;
|
|
176258
|
+
tratamiento_clp: number;
|
|
176259
|
+
prestaciones: number;
|
|
176260
|
+
};
|
|
176261
|
+
presupuestado: {
|
|
176262
|
+
total_clp: number;
|
|
176263
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176264
|
+
nuevos_clp: number;
|
|
176265
|
+
tratamiento_clp: number;
|
|
176266
|
+
presupuestos: number;
|
|
176267
|
+
};
|
|
176268
|
+
/** @description `null` with `professional_id`: a payment names no professional. */
|
|
176269
|
+
recaudacion: {
|
|
176270
|
+
total_clp: number;
|
|
176271
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176272
|
+
nuevos_clp: number;
|
|
176273
|
+
tratamiento_clp: number;
|
|
176274
|
+
pagos: number;
|
|
176275
|
+
} | null;
|
|
176276
|
+
};
|
|
176277
|
+
days: {
|
|
176278
|
+
produccion: {
|
|
176279
|
+
total_clp: number;
|
|
176280
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176281
|
+
nuevos_clp: number;
|
|
176282
|
+
tratamiento_clp: number;
|
|
176283
|
+
prestaciones: number;
|
|
176284
|
+
};
|
|
176285
|
+
presupuestado: {
|
|
176286
|
+
total_clp: number;
|
|
176287
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176288
|
+
nuevos_clp: number;
|
|
176289
|
+
tratamiento_clp: number;
|
|
176290
|
+
presupuestos: number;
|
|
176291
|
+
};
|
|
176292
|
+
/** @description `null` with `professional_id`: a payment names no professional. */
|
|
176293
|
+
recaudacion: {
|
|
176294
|
+
total_clp: number;
|
|
176295
|
+
/** @description Patients whose primera visita (Nuevo / Nuevo · reagenda) starts in the same month. */
|
|
176296
|
+
nuevos_clp: number;
|
|
176297
|
+
tratamiento_clp: number;
|
|
176298
|
+
pagos: number;
|
|
176299
|
+
} | null;
|
|
176300
|
+
day: string;
|
|
176301
|
+
}[];
|
|
176302
|
+
clinic: {
|
|
176303
|
+
/** @description Performed by this doctor (the performer). */
|
|
176304
|
+
produccion_clp: number;
|
|
176305
|
+
prestaciones: number;
|
|
176306
|
+
/** @description Real presupuestos issued ($0 and evaluación-only out), by the quoting doctor. */
|
|
176307
|
+
presupuestos: number;
|
|
176308
|
+
/** @description Their value without evaluación lines. */
|
|
176309
|
+
presupuestado_clp: number;
|
|
176310
|
+
aceptados: number;
|
|
176311
|
+
aceptacion_pct: number | null;
|
|
176312
|
+
aceptado_clp: number;
|
|
176313
|
+
/** @description Already paid on the plans issued in the period. */
|
|
176314
|
+
abonado_clp: number;
|
|
176315
|
+
nuevos_presentados: number;
|
|
176316
|
+
nuevos_aceptados: number;
|
|
176317
|
+
};
|
|
176318
|
+
by_professional: {
|
|
176319
|
+
/** Format: uuid */
|
|
176320
|
+
professional_id: string;
|
|
176321
|
+
professional_name: string;
|
|
176322
|
+
/** @description Performed by this doctor (the performer). */
|
|
176323
|
+
produccion_clp: number;
|
|
176324
|
+
prestaciones: number;
|
|
176325
|
+
/** @description Real presupuestos issued ($0 and evaluación-only out), by the quoting doctor. */
|
|
176326
|
+
presupuestos: number;
|
|
176327
|
+
/** @description Their value without evaluación lines. */
|
|
176328
|
+
presupuestado_clp: number;
|
|
176329
|
+
aceptados: number;
|
|
176330
|
+
aceptacion_pct: number | null;
|
|
176331
|
+
aceptado_clp: number;
|
|
176332
|
+
/** @description Already paid on the plans issued in the period. */
|
|
176333
|
+
abonado_clp: number;
|
|
176334
|
+
nuevos_presentados: number;
|
|
176335
|
+
nuevos_aceptados: number;
|
|
176336
|
+
}[];
|
|
176337
|
+
};
|
|
176338
|
+
ClinicIngresosMonths: {
|
|
176339
|
+
from: string;
|
|
176340
|
+
to: string;
|
|
176341
|
+
/** @enum {string} */
|
|
176342
|
+
state: "ready" | "unavailable";
|
|
176343
|
+
rules: {
|
|
176344
|
+
[key: string]: string;
|
|
176345
|
+
};
|
|
176346
|
+
months: {
|
|
176347
|
+
/** @description `YYYY-MM`. */
|
|
176348
|
+
month: string;
|
|
176349
|
+
produccion_clp: number;
|
|
176350
|
+
presupuestos: number;
|
|
176351
|
+
presupuestado_clp: number;
|
|
176352
|
+
aceptacion_pct: number | null;
|
|
176353
|
+
aceptado_clp: number;
|
|
176354
|
+
recaudacion_clp: number;
|
|
176355
|
+
}[];
|
|
176356
|
+
professionals: {
|
|
176357
|
+
/** Format: uuid */
|
|
176358
|
+
professional_id: string;
|
|
176359
|
+
professional_name: string;
|
|
176360
|
+
months: {
|
|
176361
|
+
/** @description `YYYY-MM`. */
|
|
176362
|
+
month: string;
|
|
176363
|
+
produccion_clp: number;
|
|
176364
|
+
presupuestos: number;
|
|
176365
|
+
presupuestado_clp: number;
|
|
176366
|
+
aceptacion_pct: number | null;
|
|
176367
|
+
aceptado_clp: number;
|
|
176368
|
+
}[];
|
|
176369
|
+
}[];
|
|
176370
|
+
};
|
|
176371
|
+
ClinicIngresosDay: {
|
|
176372
|
+
day: string;
|
|
176373
|
+
identity: boolean;
|
|
176374
|
+
plans: {
|
|
176375
|
+
/** Format: uuid */
|
|
176376
|
+
plan_id: string;
|
|
176377
|
+
/** @description `name` only for a caller allowed to see patient identity (`contacts:read` + `clinic:read`, plus `clinic_patients:read` for an API credential). */
|
|
176378
|
+
patient: {
|
|
176379
|
+
/** Format: uuid */
|
|
176380
|
+
id: string | null;
|
|
176381
|
+
name: string | null;
|
|
176382
|
+
};
|
|
176383
|
+
/** Format: uuid */
|
|
176384
|
+
professional_id: string | null;
|
|
176385
|
+
professional_name: string | null;
|
|
176386
|
+
total_clp: number;
|
|
176387
|
+
abonado_clp: number;
|
|
176388
|
+
deuda_clp: number;
|
|
176389
|
+
/** @enum {string} */
|
|
176390
|
+
tipo: "nuevo" | "tratamiento";
|
|
176391
|
+
/** @description Números comerciales' verdict; `null` for a $0 or evaluación-only plan. */
|
|
176392
|
+
aceptado: boolean | null;
|
|
176393
|
+
}[];
|
|
176394
|
+
payments: {
|
|
176395
|
+
/** Format: uuid */
|
|
176396
|
+
payment_id: string;
|
|
176397
|
+
time: string | null;
|
|
176398
|
+
/** @description `name` only for a caller allowed to see patient identity (`contacts:read` + `clinic:read`, plus `clinic_patients:read` for an API credential). */
|
|
176399
|
+
patient: {
|
|
176400
|
+
/** Format: uuid */
|
|
176401
|
+
id: string | null;
|
|
176402
|
+
name: string | null;
|
|
176403
|
+
};
|
|
176404
|
+
amount_clp: number;
|
|
176405
|
+
/** @enum {string} */
|
|
176406
|
+
tipo: "nuevo" | "tratamiento";
|
|
176407
|
+
}[];
|
|
176408
|
+
produccion: {
|
|
176409
|
+
/** Format: uuid */
|
|
176410
|
+
professional_id: string | null;
|
|
176411
|
+
professional_name: string | null;
|
|
176412
|
+
prestaciones: number;
|
|
176413
|
+
produccion_clp: number;
|
|
176414
|
+
}[];
|
|
176415
|
+
};
|
|
173450
176416
|
AgendaResults: {
|
|
173451
176417
|
from: string;
|
|
173452
176418
|
to: string;
|