@vitrina/api 11.35.0 → 11.36.1
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.cjs +8 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2466 -506
- package/dist/index.d.ts +2466 -506
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -13919,7 +13919,7 @@ interface paths {
|
|
|
13919
13919
|
};
|
|
13920
13920
|
/**
|
|
13921
13921
|
* List the add-on catalog, this workspace's entitlements, and live usage
|
|
13922
|
-
* @description The Complementos hub read. `catalog` is the typed feature catalog (prices are PR-reviewed code, never a runtime SKU table); `entitlements` is one row per add-on this workspace has ever held; `usage` carries the live meter for each metered add-on over the current **Santiago** month — `usage.tasador` is `{ used, free_allowance, period }`, where `used` is aggregated on read from `usage_event` (never a counter) and `free_allowance` reflects any per-workspace override, so it is the same pair of numbers the access gate decides on. Each entitlement carries `billed_by`: `vitrina` when Vitrina invoices the add-on, any other value when another party covers it (Vitrina charges nothing, so a client shows it as included rather than at the catalog price).
|
|
13922
|
+
* @description The Complementos hub read. `catalog` is the typed feature catalog (prices are PR-reviewed code, never a runtime SKU table); `entitlements` is one row per add-on this workspace has ever held; `usage` carries the live meter for each metered add-on over the current **Santiago** month — `usage.tasador` is `{ used, free_allowance, period }`, where `used` is aggregated on read from `usage_event` (never a counter) and `free_allowance` reflects any per-workspace override, so it is the same pair of numbers the access gate decides on. Each entitlement carries `billed_by`: `vitrina` when Vitrina invoices the add-on, any other value when another party covers it (Vitrina charges nothing, so a client shows it as included rather than at the catalog price). A row may also carry a time-boxed waiver: `waiver_until` is the last free calendar day (America/Santiago) and `waiver_active` says whether it covers the add-on right now; once it lapses the add-on bills normally with no further action.
|
|
13923
13923
|
*/
|
|
13924
13924
|
get: {
|
|
13925
13925
|
parameters: {
|
|
@@ -13963,9 +13963,11 @@ interface paths {
|
|
|
13963
13963
|
* "cancel_at_period_end": false,
|
|
13964
13964
|
* "canceled_at": null,
|
|
13965
13965
|
* "metadata": {},
|
|
13966
|
+
* "waiver_until": "2026-10-31",
|
|
13966
13967
|
* "created_at": "2026-09-01T12:00:00.000Z",
|
|
13967
13968
|
* "updated_at": "2026-09-01T12:00:00.000Z",
|
|
13968
|
-
* "billed_by": "vitrina"
|
|
13969
|
+
* "billed_by": "vitrina",
|
|
13970
|
+
* "waiver_active": true
|
|
13969
13971
|
* }
|
|
13970
13972
|
* ],
|
|
13971
13973
|
* "usage": {
|
|
@@ -14005,10 +14007,14 @@ interface paths {
|
|
|
14005
14007
|
metadata: {
|
|
14006
14008
|
[key: string]: unknown;
|
|
14007
14009
|
};
|
|
14010
|
+
/** @description Last calendar day (`YYYY-MM-DD`, America/Santiago) this add-on is free under a time-boxed waiver: no charge accrues through the end of that day and activation needs no payment method. It bills normally from 00:00 Santiago of the next day. `null` = no waiver. */
|
|
14011
|
+
waiver_until?: string | null;
|
|
14008
14012
|
created_at: string;
|
|
14009
14013
|
updated_at: string;
|
|
14010
14014
|
/** @description Who invoices this add-on. `vitrina` (default) = Vitrina bills it at the catalog price. Any other value names the partner whose plan covers it; Vitrina charges nothing, so show the add-on as included and never render the partner value or the catalog price. */
|
|
14011
14015
|
billed_by: string;
|
|
14016
|
+
/** @description True while the `waiver_until` waiver covers the add-on right now (resolved server-side in America/Santiago). While true, show the add-on as included until that date instead of the catalog price. */
|
|
14017
|
+
waiver_active: boolean;
|
|
14012
14018
|
}[];
|
|
14013
14019
|
usage: {
|
|
14014
14020
|
tasador: {
|
|
@@ -14096,7 +14102,7 @@ interface paths {
|
|
|
14096
14102
|
put?: never;
|
|
14097
14103
|
/**
|
|
14098
14104
|
* Self-serve activate an add-on (returns needs_enrollment without a payment mandate)
|
|
14099
|
-
* @description Grants `feature` to the workspace once an active payment mandate exists (`{ status: "active", entitlement }`); with none, answers `{ status: "needs_enrollment" }` and grants nothing — the caller routes the dealer through the Fintoc/Mercado Pago enrollment step and retries. Idempotent on an already-active feature (re-answers the same `active` row rather than erroring).
|
|
14105
|
+
* @description Grants `feature` to the workspace once an active payment mandate exists (`{ status: "active", entitlement }`); with none, answers `{ status: "needs_enrollment" }` and grants nothing — the caller routes the dealer through the Fintoc/Mercado Pago enrollment step and retries. No payment method is needed when the add-on costs the workspace nothing: its row is covered by another biller (`billed_by` other than `vitrina`) or sits inside an active `waiver_until` waiver; such an activation answers `active` and accrues no charge for the covered days. Idempotent on an already-active feature (re-answers the same `active` row rather than erroring).
|
|
14100
14106
|
*/
|
|
14101
14107
|
post: {
|
|
14102
14108
|
parameters: {
|
|
@@ -14131,6 +14137,7 @@ interface paths {
|
|
|
14131
14137
|
* "cancel_at_period_end": false,
|
|
14132
14138
|
* "canceled_at": null,
|
|
14133
14139
|
* "metadata": {},
|
|
14140
|
+
* "waiver_until": null,
|
|
14134
14141
|
* "created_at": "2026-09-23T15:00:00.000Z",
|
|
14135
14142
|
* "updated_at": "2026-09-23T15:00:00.000Z"
|
|
14136
14143
|
* }
|
|
@@ -19946,6 +19953,9 @@ interface paths {
|
|
|
19946
19953
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
19947
19954
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
19948
19955
|
* "won_lost_reason": null,
|
|
19956
|
+
* "lost_reason": null,
|
|
19957
|
+
* "lost_reason_source": null,
|
|
19958
|
+
* "lost_reason_at": null,
|
|
19949
19959
|
* "closed_at": null,
|
|
19950
19960
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
19951
19961
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -20000,6 +20010,9 @@ interface paths {
|
|
|
20000
20010
|
* "temperature_reason": null,
|
|
20001
20011
|
* "temperature_at": null,
|
|
20002
20012
|
* "won_lost_reason": null,
|
|
20013
|
+
* "lost_reason": null,
|
|
20014
|
+
* "lost_reason_source": null,
|
|
20015
|
+
* "lost_reason_at": null,
|
|
20003
20016
|
* "closed_at": null,
|
|
20004
20017
|
* "created_by": null,
|
|
20005
20018
|
* "created_at": "2026-09-19T09:12:44.000Z",
|
|
@@ -20194,6 +20207,9 @@ interface paths {
|
|
|
20194
20207
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
20195
20208
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
20196
20209
|
* "won_lost_reason": null,
|
|
20210
|
+
* "lost_reason": null,
|
|
20211
|
+
* "lost_reason_source": null,
|
|
20212
|
+
* "lost_reason_at": null,
|
|
20197
20213
|
* "closed_at": null,
|
|
20198
20214
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
20199
20215
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -20374,6 +20390,9 @@ interface paths {
|
|
|
20374
20390
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
20375
20391
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
20376
20392
|
* "won_lost_reason": null,
|
|
20393
|
+
* "lost_reason": null,
|
|
20394
|
+
* "lost_reason_source": null,
|
|
20395
|
+
* "lost_reason_at": null,
|
|
20377
20396
|
* "closed_at": null,
|
|
20378
20397
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
20379
20398
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -21064,6 +21083,9 @@ interface paths {
|
|
|
21064
21083
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
21065
21084
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
21066
21085
|
* "won_lost_reason": null,
|
|
21086
|
+
* "lost_reason": null,
|
|
21087
|
+
* "lost_reason_source": null,
|
|
21088
|
+
* "lost_reason_at": null,
|
|
21067
21089
|
* "closed_at": null,
|
|
21068
21090
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
21069
21091
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -21128,6 +21150,9 @@ interface paths {
|
|
|
21128
21150
|
* "temperature_reason": null,
|
|
21129
21151
|
* "temperature_at": null,
|
|
21130
21152
|
* "won_lost_reason": null,
|
|
21153
|
+
* "lost_reason": null,
|
|
21154
|
+
* "lost_reason_source": null,
|
|
21155
|
+
* "lost_reason_at": null,
|
|
21131
21156
|
* "closed_at": null,
|
|
21132
21157
|
* "created_by": null,
|
|
21133
21158
|
* "created_at": "2026-09-19T09:12:44.000Z",
|
|
@@ -21405,6 +21430,9 @@ interface paths {
|
|
|
21405
21430
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
21406
21431
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
21407
21432
|
* "won_lost_reason": null,
|
|
21433
|
+
* "lost_reason": null,
|
|
21434
|
+
* "lost_reason_source": null,
|
|
21435
|
+
* "lost_reason_at": null,
|
|
21408
21436
|
* "closed_at": null,
|
|
21409
21437
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
21410
21438
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -21534,6 +21562,8 @@ interface paths {
|
|
|
21534
21562
|
/** @enum {string|null} */
|
|
21535
21563
|
temperature?: "hot" | "warm" | "cold" | null;
|
|
21536
21564
|
temperature_reason?: string | null;
|
|
21565
|
+
/** @enum {string} */
|
|
21566
|
+
lost_reason?: "bought_elsewhere" | "financing_rejected" | "unit_unavailable" | "price" | "not_ready" | "unresponsive" | "other";
|
|
21537
21567
|
};
|
|
21538
21568
|
};
|
|
21539
21569
|
};
|
|
@@ -21575,6 +21605,9 @@ interface paths {
|
|
|
21575
21605
|
* "temperature_reason": "volvió a escribir pidiendo la reserva",
|
|
21576
21606
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
21577
21607
|
* "won_lost_reason": null,
|
|
21608
|
+
* "lost_reason": null,
|
|
21609
|
+
* "lost_reason_source": null,
|
|
21610
|
+
* "lost_reason_at": null,
|
|
21578
21611
|
* "closed_at": null,
|
|
21579
21612
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
21580
21613
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -21993,6 +22026,9 @@ interface paths {
|
|
|
21993
22026
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
21994
22027
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
21995
22028
|
* "won_lost_reason": null,
|
|
22029
|
+
* "lost_reason": null,
|
|
22030
|
+
* "lost_reason_source": null,
|
|
22031
|
+
* "lost_reason_at": null,
|
|
21996
22032
|
* "closed_at": null,
|
|
21997
22033
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
21998
22034
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -22165,6 +22201,9 @@ interface paths {
|
|
|
22165
22201
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
22166
22202
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
22167
22203
|
* "won_lost_reason": null,
|
|
22204
|
+
* "lost_reason": null,
|
|
22205
|
+
* "lost_reason_source": null,
|
|
22206
|
+
* "lost_reason_at": null,
|
|
22168
22207
|
* "closed_at": null,
|
|
22169
22208
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
22170
22209
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -22338,6 +22377,9 @@ interface paths {
|
|
|
22338
22377
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
22339
22378
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
22340
22379
|
* "won_lost_reason": null,
|
|
22380
|
+
* "lost_reason": null,
|
|
22381
|
+
* "lost_reason_source": null,
|
|
22382
|
+
* "lost_reason_at": null,
|
|
22341
22383
|
* "closed_at": null,
|
|
22342
22384
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
22343
22385
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -22513,6 +22555,9 @@ interface paths {
|
|
|
22513
22555
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
22514
22556
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
22515
22557
|
* "won_lost_reason": "cerró con financiamiento propio",
|
|
22558
|
+
* "lost_reason": null,
|
|
22559
|
+
* "lost_reason_source": null,
|
|
22560
|
+
* "lost_reason_at": null,
|
|
22516
22561
|
* "closed_at": "2026-09-22T08:41:32.977Z",
|
|
22517
22562
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
22518
22563
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -22686,6 +22731,9 @@ interface paths {
|
|
|
22686
22731
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
22687
22732
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
22688
22733
|
* "won_lost_reason": "compró en otra parte",
|
|
22734
|
+
* "lost_reason": "bought_elsewhere",
|
|
22735
|
+
* "lost_reason_source": "jev",
|
|
22736
|
+
* "lost_reason_at": "2026-09-22T08:44:12.501Z",
|
|
22689
22737
|
* "closed_at": "2026-09-22T08:44:10.331Z",
|
|
22690
22738
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
22691
22739
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -22859,6 +22907,9 @@ interface paths {
|
|
|
22859
22907
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
22860
22908
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
22861
22909
|
* "won_lost_reason": "buscaba un servicio que no ofrecemos",
|
|
22910
|
+
* "lost_reason": null,
|
|
22911
|
+
* "lost_reason_source": null,
|
|
22912
|
+
* "lost_reason_at": null,
|
|
22862
22913
|
* "closed_at": "2026-09-22T08:44:10.331Z",
|
|
22863
22914
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
22864
22915
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -23017,6 +23068,9 @@ interface paths {
|
|
|
23017
23068
|
* "temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
|
|
23018
23069
|
* "temperature_at": "2026-09-21T14:02:11.000Z",
|
|
23019
23070
|
* "won_lost_reason": null,
|
|
23071
|
+
* "lost_reason": null,
|
|
23072
|
+
* "lost_reason_source": null,
|
|
23073
|
+
* "lost_reason_at": null,
|
|
23020
23074
|
* "closed_at": null,
|
|
23021
23075
|
* "created_by": "11111111-0000-4000-8000-000000000001",
|
|
23022
23076
|
* "created_at": "2026-09-18T13:44:02.115Z",
|
|
@@ -28118,7 +28172,7 @@ interface paths {
|
|
|
28118
28172
|
* A contact’s scope-aware consent / do-not-contact ledger
|
|
28119
28173
|
* @description Append-only history, newest fact first — this is the surface that can answer «since when, and how do you know».
|
|
28120
28174
|
*
|
|
28121
|
-
* Each row is one fact about one `channel` (`whatsapp|email|voice|any`) in one `scope` (`marketing|service|promised_followup|all_proactive`). A marketing block does NOT block service messages; a current `all_proactive` block outranks every scope.
|
|
28175
|
+
* Each row is one fact about one `channel` (`whatsapp|email|voice|instagram|messenger|any`) in one `scope` (`marketing|service|promised_followup|all_proactive`). A marketing block does NOT block service messages; a current `all_proactive` block outranks every scope.
|
|
28122
28176
|
*
|
|
28123
28177
|
* A superseded row stays readable rather than being overwritten, so the evidence trail survives the revocation.
|
|
28124
28178
|
*/
|
|
@@ -28260,7 +28314,7 @@ interface paths {
|
|
|
28260
28314
|
*/
|
|
28261
28315
|
"application/json": {
|
|
28262
28316
|
/** @enum {string} */
|
|
28263
|
-
channel: "whatsapp" | "email" | "voice" | "any";
|
|
28317
|
+
channel: "whatsapp" | "email" | "voice" | "instagram" | "messenger" | "any";
|
|
28264
28318
|
/** @enum {string} */
|
|
28265
28319
|
scope: "marketing" | "service" | "promised_followup" | "all_proactive";
|
|
28266
28320
|
/** @enum {string} */
|
|
@@ -69292,7 +69346,7 @@ interface paths {
|
|
|
69292
69346
|
};
|
|
69293
69347
|
trace?: never;
|
|
69294
69348
|
};
|
|
69295
|
-
"/clinic/
|
|
69349
|
+
"/clinic/patients/{id}/auto-links": {
|
|
69296
69350
|
parameters: {
|
|
69297
69351
|
query?: never;
|
|
69298
69352
|
header?: never;
|
|
@@ -69300,30 +69354,23 @@ interface paths {
|
|
|
69300
69354
|
cookie?: never;
|
|
69301
69355
|
};
|
|
69302
69356
|
/**
|
|
69303
|
-
*
|
|
69304
|
-
* @description The
|
|
69357
|
+
* Automatic contact links of a patient (Ads identity only)
|
|
69358
|
+
* @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 — 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.
|
|
69305
69359
|
*
|
|
69306
|
-
* **Connected apps:**
|
|
69360
|
+
* **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.
|
|
69307
69361
|
*/
|
|
69308
69362
|
get: {
|
|
69309
69363
|
parameters: {
|
|
69310
|
-
query?:
|
|
69311
|
-
/** @description First day of the window, inclusive. Defaults to 90 days before `to`. */
|
|
69312
|
-
from?: string;
|
|
69313
|
-
/** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
|
|
69314
|
-
to?: string;
|
|
69315
|
-
/** @description One sucursal. Omit for all of them. */
|
|
69316
|
-
location_id?: string;
|
|
69317
|
-
/** @description One profesional. A foreign id is a 404, never an empty report. */
|
|
69318
|
-
professional_id?: string;
|
|
69319
|
-
};
|
|
69364
|
+
query?: never;
|
|
69320
69365
|
header?: never;
|
|
69321
|
-
path
|
|
69366
|
+
path: {
|
|
69367
|
+
id: string;
|
|
69368
|
+
};
|
|
69322
69369
|
cookie?: never;
|
|
69323
69370
|
};
|
|
69324
69371
|
requestBody?: never;
|
|
69325
69372
|
responses: {
|
|
69326
|
-
/** @description
|
|
69373
|
+
/** @description Patient auto-links */
|
|
69327
69374
|
200: {
|
|
69328
69375
|
headers: {
|
|
69329
69376
|
[name: string]: unknown;
|
|
@@ -69332,151 +69379,538 @@ interface paths {
|
|
|
69332
69379
|
/**
|
|
69333
69380
|
* @example {
|
|
69334
69381
|
* "data": {
|
|
69335
|
-
* "
|
|
69336
|
-
* "to": "2026-08-29",
|
|
69337
|
-
* "timezone": "America/Santiago",
|
|
69338
|
-
* "location_id": null,
|
|
69339
|
-
* "professional_id": null,
|
|
69340
|
-
* "state": "ready",
|
|
69341
|
-
* "state_reason": null,
|
|
69342
|
-
* "regime": "evidencia",
|
|
69343
|
-
* "regime_label": "Aceptación por evidencia",
|
|
69344
|
-
* "regime_rule": "Leído desde tu software de agenda: un presupuesto cuenta como aceptado cuando se realizó una de sus prestaciones o el paciente agendó una cita después de recibirlo.",
|
|
69345
|
-
* "source": {
|
|
69346
|
-
* "kind": "mirror",
|
|
69347
|
-
* "synced_at": "2026-08-30T03:10:00.000Z"
|
|
69348
|
-
* },
|
|
69349
|
-
* "formulas": {
|
|
69350
|
-
* "acceptance": "mentores_2026_09_25",
|
|
69351
|
-
* "cierre": "cierre_2026_09_25",
|
|
69352
|
-
* "first_visit": "propuesta",
|
|
69353
|
-
* "second_visit": "propuesta",
|
|
69354
|
-
* "botados": "propuesta"
|
|
69355
|
-
* },
|
|
69356
|
-
* "headline": {
|
|
69357
|
-
* "collected_clp": 48500000,
|
|
69358
|
-
* "previous_collected_clp": 44100000,
|
|
69359
|
-
* "delta_pct": 10,
|
|
69360
|
-
* "previous_from": "2026-03-03",
|
|
69361
|
-
* "previous_to": "2026-05-31",
|
|
69362
|
-
* "rule": "Lo cobrado en el período: todos los pagos recibidos, sin los anulados. Se compara con el período anterior del mismo largo."
|
|
69363
|
-
* },
|
|
69364
|
-
* "acceptance": {
|
|
69365
|
-
* "presented": 420,
|
|
69366
|
-
* "accepted": 231,
|
|
69367
|
-
* "rate": 55,
|
|
69368
|
-
* "same_day": 118,
|
|
69369
|
-
* "later": 113,
|
|
69370
|
-
* "cita_only": 14,
|
|
69371
|
-
* "pending": 36,
|
|
69372
|
-
* "presented_clp": 142000000,
|
|
69373
|
-
* "accepted_clp": 71300000,
|
|
69374
|
-
* "rate_30d": 47.2,
|
|
69375
|
-
* "rate_60d": 53.8,
|
|
69376
|
-
* "formula": "mentores_2026_09_25",
|
|
69377
|
-
* "window_days": 60,
|
|
69378
|
-
* "long_window_days": 90,
|
|
69379
|
-
* "rule": "Presupuestos aceptados ÷ presupuestos presentados, cada presupuesto una vez."
|
|
69380
|
-
* },
|
|
69381
|
-
* "cierres": {
|
|
69382
|
-
* "count": 180,
|
|
69383
|
-
* "value_clp": 58900000,
|
|
69384
|
-
* "accepted_without_payment": 51,
|
|
69385
|
-
* "formula": "cierre_2026_09_25",
|
|
69386
|
-
* "rule": "Un cierre es el primer pago de un presupuesto aceptado."
|
|
69387
|
-
* },
|
|
69388
|
-
* "cohorts": [
|
|
69389
|
-
* {
|
|
69390
|
-
* "month": "2026-06",
|
|
69391
|
-
* "presented": 140,
|
|
69392
|
-
* "accepted": 80,
|
|
69393
|
-
* "rate": 57.1,
|
|
69394
|
-
* "same_day": 41,
|
|
69395
|
-
* "later": 39,
|
|
69396
|
-
* "cita_only": 2,
|
|
69397
|
-
* "pending": 0,
|
|
69398
|
-
* "presented_clp": 47000000,
|
|
69399
|
-
* "accepted_clp": 24800000,
|
|
69400
|
-
* "rate_30d": 49.3,
|
|
69401
|
-
* "rate_60d": 56.4,
|
|
69402
|
-
* "mature": true
|
|
69403
|
-
* }
|
|
69404
|
-
* ],
|
|
69405
|
-
* "by_professional": [
|
|
69382
|
+
* "data": [
|
|
69406
69383
|
* {
|
|
69407
|
-
* "
|
|
69408
|
-
* "
|
|
69409
|
-
* "
|
|
69410
|
-
* "
|
|
69411
|
-
* "
|
|
69412
|
-
* "
|
|
69413
|
-
* "
|
|
69414
|
-
* "
|
|
69415
|
-
* "
|
|
69416
|
-
* "
|
|
69417
|
-
* "
|
|
69418
|
-
* "
|
|
69419
|
-
* "
|
|
69384
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
69385
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
69386
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
69387
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
69388
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
69389
|
+
* "status": "live",
|
|
69390
|
+
* "method": "phone_unique",
|
|
69391
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
69392
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
69393
|
+
* "revoked_at": null,
|
|
69394
|
+
* "revoked_reason": null,
|
|
69395
|
+
* "sent_count": 3,
|
|
69396
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z"
|
|
69420
69397
|
* }
|
|
69421
|
-
* ]
|
|
69422
|
-
*
|
|
69423
|
-
*
|
|
69424
|
-
|
|
69398
|
+
* ]
|
|
69399
|
+
* }
|
|
69400
|
+
* }
|
|
69401
|
+
*/
|
|
69402
|
+
"application/json": {
|
|
69403
|
+
data?: unknown;
|
|
69404
|
+
meta?: {
|
|
69405
|
+
[key: string]: unknown;
|
|
69406
|
+
};
|
|
69407
|
+
};
|
|
69408
|
+
};
|
|
69409
|
+
};
|
|
69410
|
+
/** @description Validation error */
|
|
69411
|
+
400: {
|
|
69412
|
+
headers: {
|
|
69413
|
+
[name: string]: unknown;
|
|
69414
|
+
};
|
|
69415
|
+
content: {
|
|
69416
|
+
"application/json": components["schemas"]["Error"];
|
|
69417
|
+
};
|
|
69418
|
+
};
|
|
69419
|
+
/** @description Unauthorized */
|
|
69420
|
+
401: {
|
|
69421
|
+
headers: {
|
|
69422
|
+
[name: string]: unknown;
|
|
69423
|
+
};
|
|
69424
|
+
content: {
|
|
69425
|
+
"application/json": components["schemas"]["Error"];
|
|
69426
|
+
};
|
|
69427
|
+
};
|
|
69428
|
+
/** @description Forbidden */
|
|
69429
|
+
403: {
|
|
69430
|
+
headers: {
|
|
69431
|
+
[name: string]: unknown;
|
|
69432
|
+
};
|
|
69433
|
+
content: {
|
|
69434
|
+
"application/json": components["schemas"]["Error"];
|
|
69435
|
+
};
|
|
69436
|
+
};
|
|
69437
|
+
/** @description Not found */
|
|
69438
|
+
404: {
|
|
69439
|
+
headers: {
|
|
69440
|
+
[name: string]: unknown;
|
|
69441
|
+
};
|
|
69442
|
+
content: {
|
|
69443
|
+
"application/json": components["schemas"]["Error"];
|
|
69444
|
+
};
|
|
69445
|
+
};
|
|
69446
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
69447
|
+
409: {
|
|
69448
|
+
headers: {
|
|
69449
|
+
[name: string]: unknown;
|
|
69450
|
+
};
|
|
69451
|
+
content: {
|
|
69452
|
+
"application/json": components["schemas"]["Error"];
|
|
69453
|
+
};
|
|
69454
|
+
};
|
|
69455
|
+
/** @description Rate limited */
|
|
69456
|
+
429: {
|
|
69457
|
+
headers: {
|
|
69458
|
+
[name: string]: unknown;
|
|
69459
|
+
};
|
|
69460
|
+
content: {
|
|
69461
|
+
"application/json": components["schemas"]["Error"];
|
|
69462
|
+
};
|
|
69463
|
+
};
|
|
69464
|
+
};
|
|
69465
|
+
};
|
|
69466
|
+
put?: never;
|
|
69467
|
+
post?: never;
|
|
69468
|
+
delete?: never;
|
|
69469
|
+
options?: never;
|
|
69470
|
+
head?: never;
|
|
69471
|
+
patch?: never;
|
|
69472
|
+
trace?: never;
|
|
69473
|
+
};
|
|
69474
|
+
"/clinic/contacts/{contactId}/auto-links": {
|
|
69475
|
+
parameters: {
|
|
69476
|
+
query?: never;
|
|
69477
|
+
header?: never;
|
|
69478
|
+
path?: never;
|
|
69479
|
+
cookie?: never;
|
|
69480
|
+
};
|
|
69481
|
+
/**
|
|
69482
|
+
* Patients automatically linked to a contact (Ads identity only)
|
|
69483
|
+
* @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 — 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.
|
|
69484
|
+
*
|
|
69485
|
+
* **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.
|
|
69486
|
+
*/
|
|
69487
|
+
get: {
|
|
69488
|
+
parameters: {
|
|
69489
|
+
query?: never;
|
|
69490
|
+
header?: never;
|
|
69491
|
+
path: {
|
|
69492
|
+
contactId: string;
|
|
69493
|
+
};
|
|
69494
|
+
cookie?: never;
|
|
69495
|
+
};
|
|
69496
|
+
requestBody?: never;
|
|
69497
|
+
responses: {
|
|
69498
|
+
/** @description Contact auto-links */
|
|
69499
|
+
200: {
|
|
69500
|
+
headers: {
|
|
69501
|
+
[name: string]: unknown;
|
|
69502
|
+
};
|
|
69503
|
+
content: {
|
|
69504
|
+
/**
|
|
69505
|
+
* @example {
|
|
69506
|
+
* "data": {
|
|
69507
|
+
* "data": [
|
|
69425
69508
|
* {
|
|
69426
|
-
* "
|
|
69427
|
-
* "
|
|
69428
|
-
* "
|
|
69429
|
-
* "
|
|
69430
|
-
* "
|
|
69431
|
-
* "
|
|
69509
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
69510
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
69511
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
69512
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
69513
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
69514
|
+
* "status": "live",
|
|
69515
|
+
* "method": "phone_unique",
|
|
69516
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
69517
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
69518
|
+
* "revoked_at": null,
|
|
69519
|
+
* "revoked_reason": null,
|
|
69520
|
+
* "sent_count": 3,
|
|
69521
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z"
|
|
69432
69522
|
* }
|
|
69433
|
-
* ]
|
|
69434
|
-
* "first_visit": {
|
|
69435
|
-
* "formula": "propuesta",
|
|
69436
|
-
* "patients": 210,
|
|
69437
|
-
* "paid": 97,
|
|
69438
|
-
* "rate": 46.2,
|
|
69439
|
-
* "rule": "Fórmula propuesta."
|
|
69440
|
-
* },
|
|
69441
|
-
* "second_visit": {
|
|
69442
|
-
* "formula": "propuesta",
|
|
69443
|
-
* "eligible": 113,
|
|
69444
|
-
* "converted": 29,
|
|
69445
|
-
* "rate": 25.7,
|
|
69446
|
-
* "rule": "Fórmula propuesta."
|
|
69447
|
-
* },
|
|
69448
|
-
* "botados": {
|
|
69449
|
-
* "unaccepted": {
|
|
69450
|
-
* "count": 88,
|
|
69451
|
-
* "clp": 31200000
|
|
69452
|
-
* },
|
|
69453
|
-
* "accepted_unscheduled": {
|
|
69454
|
-
* "count": 17,
|
|
69455
|
-
* "clp": 6400000
|
|
69456
|
-
* },
|
|
69457
|
-
* "mid_treatment_no_future_cita": {
|
|
69458
|
-
* "count": 23,
|
|
69459
|
-
* "clp": 9800000
|
|
69460
|
-
* },
|
|
69461
|
-
* "formula": "propuesta",
|
|
69462
|
-
* "basis": "live_last_6_months",
|
|
69463
|
-
* "total": {
|
|
69464
|
-
* "count": 128,
|
|
69465
|
-
* "clp": 47400000
|
|
69466
|
-
* },
|
|
69467
|
-
* "focus": "unaccepted",
|
|
69468
|
-
* "rule": "Fórmula propuesta."
|
|
69469
|
-
* },
|
|
69470
|
-
* "coverage": {
|
|
69471
|
-
* "plans_without_lines": 0,
|
|
69472
|
-
* "excluded_zero": 301,
|
|
69473
|
-
* "excluded_entry_only": 92
|
|
69474
|
-
* }
|
|
69523
|
+
* ]
|
|
69475
69524
|
* }
|
|
69476
69525
|
* }
|
|
69477
69526
|
*/
|
|
69478
69527
|
"application/json": {
|
|
69479
|
-
data
|
|
69528
|
+
data?: unknown;
|
|
69529
|
+
meta?: {
|
|
69530
|
+
[key: string]: unknown;
|
|
69531
|
+
};
|
|
69532
|
+
};
|
|
69533
|
+
};
|
|
69534
|
+
};
|
|
69535
|
+
/** @description Validation error */
|
|
69536
|
+
400: {
|
|
69537
|
+
headers: {
|
|
69538
|
+
[name: string]: unknown;
|
|
69539
|
+
};
|
|
69540
|
+
content: {
|
|
69541
|
+
"application/json": components["schemas"]["Error"];
|
|
69542
|
+
};
|
|
69543
|
+
};
|
|
69544
|
+
/** @description Unauthorized */
|
|
69545
|
+
401: {
|
|
69546
|
+
headers: {
|
|
69547
|
+
[name: string]: unknown;
|
|
69548
|
+
};
|
|
69549
|
+
content: {
|
|
69550
|
+
"application/json": components["schemas"]["Error"];
|
|
69551
|
+
};
|
|
69552
|
+
};
|
|
69553
|
+
/** @description Forbidden */
|
|
69554
|
+
403: {
|
|
69555
|
+
headers: {
|
|
69556
|
+
[name: string]: unknown;
|
|
69557
|
+
};
|
|
69558
|
+
content: {
|
|
69559
|
+
"application/json": components["schemas"]["Error"];
|
|
69560
|
+
};
|
|
69561
|
+
};
|
|
69562
|
+
/** @description Not found */
|
|
69563
|
+
404: {
|
|
69564
|
+
headers: {
|
|
69565
|
+
[name: string]: unknown;
|
|
69566
|
+
};
|
|
69567
|
+
content: {
|
|
69568
|
+
"application/json": components["schemas"]["Error"];
|
|
69569
|
+
};
|
|
69570
|
+
};
|
|
69571
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
69572
|
+
409: {
|
|
69573
|
+
headers: {
|
|
69574
|
+
[name: string]: unknown;
|
|
69575
|
+
};
|
|
69576
|
+
content: {
|
|
69577
|
+
"application/json": components["schemas"]["Error"];
|
|
69578
|
+
};
|
|
69579
|
+
};
|
|
69580
|
+
/** @description Rate limited */
|
|
69581
|
+
429: {
|
|
69582
|
+
headers: {
|
|
69583
|
+
[name: string]: unknown;
|
|
69584
|
+
};
|
|
69585
|
+
content: {
|
|
69586
|
+
"application/json": components["schemas"]["Error"];
|
|
69587
|
+
};
|
|
69588
|
+
};
|
|
69589
|
+
};
|
|
69590
|
+
};
|
|
69591
|
+
put?: never;
|
|
69592
|
+
post?: never;
|
|
69593
|
+
delete?: never;
|
|
69594
|
+
options?: never;
|
|
69595
|
+
head?: never;
|
|
69596
|
+
patch?: never;
|
|
69597
|
+
trace?: never;
|
|
69598
|
+
};
|
|
69599
|
+
"/clinic/auto-links/{id}/reject": {
|
|
69600
|
+
parameters: {
|
|
69601
|
+
query?: never;
|
|
69602
|
+
header?: never;
|
|
69603
|
+
path?: never;
|
|
69604
|
+
cookie?: never;
|
|
69605
|
+
};
|
|
69606
|
+
get?: never;
|
|
69607
|
+
put?: never;
|
|
69608
|
+
/**
|
|
69609
|
+
* «No es esta persona» — reject an automatic link for good
|
|
69610
|
+
* @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.
|
|
69611
|
+
*
|
|
69612
|
+
* **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.
|
|
69613
|
+
*/
|
|
69614
|
+
post: {
|
|
69615
|
+
parameters: {
|
|
69616
|
+
query?: never;
|
|
69617
|
+
header?: {
|
|
69618
|
+
/** @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. */
|
|
69619
|
+
"Idempotency-Key"?: string;
|
|
69620
|
+
};
|
|
69621
|
+
path: {
|
|
69622
|
+
id: string;
|
|
69623
|
+
};
|
|
69624
|
+
cookie?: never;
|
|
69625
|
+
};
|
|
69626
|
+
requestBody?: {
|
|
69627
|
+
content: {
|
|
69628
|
+
/** @example {} */
|
|
69629
|
+
"application/json": Record<string, never>;
|
|
69630
|
+
};
|
|
69631
|
+
};
|
|
69632
|
+
responses: {
|
|
69633
|
+
/** @description Rejected auto-link */
|
|
69634
|
+
200: {
|
|
69635
|
+
headers: {
|
|
69636
|
+
[name: string]: unknown;
|
|
69637
|
+
};
|
|
69638
|
+
content: {
|
|
69639
|
+
/**
|
|
69640
|
+
* @example {
|
|
69641
|
+
* "data": {
|
|
69642
|
+
* "id": "a7a7a7a7-0000-4000-8000-000000000001",
|
|
69643
|
+
* "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
|
|
69644
|
+
* "contact_id": "1a73af9e-0000-4000-8000-000000000001",
|
|
69645
|
+
* "patient_name": "María José Fuentes Lagos",
|
|
69646
|
+
* "contact_name": "María José Fuentes Lagos",
|
|
69647
|
+
* "status": "rejected",
|
|
69648
|
+
* "method": "phone_unique",
|
|
69649
|
+
* "matched_at": "2026-09-27T14:10:02.118Z",
|
|
69650
|
+
* "run_id": "a8a8a8a8-0000-4000-8000-000000000001",
|
|
69651
|
+
* "revoked_at": "2026-09-28T15:31:09.004Z",
|
|
69652
|
+
* "revoked_reason": "rejected",
|
|
69653
|
+
* "sent_count": 3,
|
|
69654
|
+
* "last_sent_at": "2026-09-28T12:02:40.551Z",
|
|
69655
|
+
* "withheld_outcomes": 1
|
|
69656
|
+
* }
|
|
69657
|
+
* }
|
|
69658
|
+
*/
|
|
69659
|
+
"application/json": {
|
|
69660
|
+
data?: unknown;
|
|
69661
|
+
meta?: {
|
|
69662
|
+
[key: string]: unknown;
|
|
69663
|
+
};
|
|
69664
|
+
};
|
|
69665
|
+
};
|
|
69666
|
+
};
|
|
69667
|
+
/** @description Validation error */
|
|
69668
|
+
400: {
|
|
69669
|
+
headers: {
|
|
69670
|
+
[name: string]: unknown;
|
|
69671
|
+
};
|
|
69672
|
+
content: {
|
|
69673
|
+
"application/json": components["schemas"]["Error"];
|
|
69674
|
+
};
|
|
69675
|
+
};
|
|
69676
|
+
/** @description Unauthorized */
|
|
69677
|
+
401: {
|
|
69678
|
+
headers: {
|
|
69679
|
+
[name: string]: unknown;
|
|
69680
|
+
};
|
|
69681
|
+
content: {
|
|
69682
|
+
"application/json": components["schemas"]["Error"];
|
|
69683
|
+
};
|
|
69684
|
+
};
|
|
69685
|
+
/** @description Forbidden */
|
|
69686
|
+
403: {
|
|
69687
|
+
headers: {
|
|
69688
|
+
[name: string]: unknown;
|
|
69689
|
+
};
|
|
69690
|
+
content: {
|
|
69691
|
+
"application/json": components["schemas"]["Error"];
|
|
69692
|
+
};
|
|
69693
|
+
};
|
|
69694
|
+
/** @description Not found */
|
|
69695
|
+
404: {
|
|
69696
|
+
headers: {
|
|
69697
|
+
[name: string]: unknown;
|
|
69698
|
+
};
|
|
69699
|
+
content: {
|
|
69700
|
+
"application/json": components["schemas"]["Error"];
|
|
69701
|
+
};
|
|
69702
|
+
};
|
|
69703
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
69704
|
+
409: {
|
|
69705
|
+
headers: {
|
|
69706
|
+
[name: string]: unknown;
|
|
69707
|
+
};
|
|
69708
|
+
content: {
|
|
69709
|
+
"application/json": components["schemas"]["Error"];
|
|
69710
|
+
};
|
|
69711
|
+
};
|
|
69712
|
+
/** @description Rate limited */
|
|
69713
|
+
429: {
|
|
69714
|
+
headers: {
|
|
69715
|
+
[name: string]: unknown;
|
|
69716
|
+
};
|
|
69717
|
+
content: {
|
|
69718
|
+
"application/json": components["schemas"]["Error"];
|
|
69719
|
+
};
|
|
69720
|
+
};
|
|
69721
|
+
};
|
|
69722
|
+
};
|
|
69723
|
+
delete?: never;
|
|
69724
|
+
options?: never;
|
|
69725
|
+
head?: never;
|
|
69726
|
+
patch?: never;
|
|
69727
|
+
trace?: never;
|
|
69728
|
+
};
|
|
69729
|
+
"/clinic/insights/comercial": {
|
|
69730
|
+
parameters: {
|
|
69731
|
+
query?: never;
|
|
69732
|
+
header?: never;
|
|
69733
|
+
path?: never;
|
|
69734
|
+
cookie?: never;
|
|
69735
|
+
};
|
|
69736
|
+
/**
|
|
69737
|
+
* Commercial numbers: presupuesto acceptance, cierres, cash, botados
|
|
69738
|
+
* @description The clinic's commercial numbers, aggregates only (counts, CLP, percentages, months and professional names; never a patient). `regime` says how acceptance is read: `evidencia` when the revenue mirror is on (a non-entry line performed, or a cita booked after the presupuesto, inside its window), `explicita` otherwise (the acceptance the clinic recorded). Acceptance is by COUNT of presupuestos, one per lineage; $0 and entry-only presupuestos are out of both sides; the window is 60 days (90 for ortodoncia and implantología); the rate goes to the professional who issued the presupuesto. Presupuestos ISSUED in the window form the acceptance cohort (`cohorts` by issue month with 30- and 60-day reads). A cierre is the first payment on an accepted presupuesto: once per presupuesto, dated on that payment, valued at the full accepted value. `headline` is the cash collected in the window against the previous window of the same length. `first_visit`, `second_visit` and `botados` carry `formula: propuesta`; `botados` is a live worklist over the last six months. Every KPI carries its `formula` and a printable `rule`; a rate with no denominator is `null`, never 0. `state` is `empty`, `settling` (presupuesto lines still being read; `state_reason` says so) or `ready`. Requires `clinic_money:read` (or `clinic_insights:read`, which reads the same aggregates). Accepts `from` / `to` (bare `YYYY-MM-DD`, `to` INCLUSIVE; default the 90 days ending today in the clinic's zone), `location_id` and `professional_id`. With `professional_id`, cash (`headline`, `months[].collected_clp`) is `null`: a payment belongs to the patient, not to a professional. A caller WITHOUT `clinic_money:read` always reads one fixed window — the last 3 closed calendar months — whatever range or filter it asks (`suppression.filters_ignored`), with every count or CLP resting on 1–4 cases `null`, rates over fewer than 5 cases `null`, complementary suppression over professionals, cohorts and botados lists, and month rows carrying only cash.
|
|
69739
|
+
*
|
|
69740
|
+
* **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`.
|
|
69741
|
+
*/
|
|
69742
|
+
get: {
|
|
69743
|
+
parameters: {
|
|
69744
|
+
query?: {
|
|
69745
|
+
/** @description First day of the window, inclusive. Defaults to 90 days before `to`. */
|
|
69746
|
+
from?: string;
|
|
69747
|
+
/** @description Last day of the window, INCLUSIVE. Defaults to today in the clinic's zone. */
|
|
69748
|
+
to?: string;
|
|
69749
|
+
/** @description One sucursal. Omit for all of them. */
|
|
69750
|
+
location_id?: string;
|
|
69751
|
+
/** @description One profesional. A foreign id is a 404, never an empty report. */
|
|
69752
|
+
professional_id?: string;
|
|
69753
|
+
};
|
|
69754
|
+
header?: never;
|
|
69755
|
+
path?: never;
|
|
69756
|
+
cookie?: never;
|
|
69757
|
+
};
|
|
69758
|
+
requestBody?: never;
|
|
69759
|
+
responses: {
|
|
69760
|
+
/** @description Clinic commercial numbers */
|
|
69761
|
+
200: {
|
|
69762
|
+
headers: {
|
|
69763
|
+
[name: string]: unknown;
|
|
69764
|
+
};
|
|
69765
|
+
content: {
|
|
69766
|
+
/**
|
|
69767
|
+
* @example {
|
|
69768
|
+
* "data": {
|
|
69769
|
+
* "from": "2026-06-01",
|
|
69770
|
+
* "to": "2026-08-29",
|
|
69771
|
+
* "timezone": "America/Santiago",
|
|
69772
|
+
* "location_id": null,
|
|
69773
|
+
* "professional_id": null,
|
|
69774
|
+
* "state": "ready",
|
|
69775
|
+
* "state_reason": null,
|
|
69776
|
+
* "regime": "evidencia",
|
|
69777
|
+
* "regime_label": "Aceptación por evidencia",
|
|
69778
|
+
* "regime_rule": "Leído desde tu software de agenda: un presupuesto cuenta como aceptado cuando se realizó una de sus prestaciones o el paciente agendó una cita después de recibirlo.",
|
|
69779
|
+
* "source": {
|
|
69780
|
+
* "kind": "mirror",
|
|
69781
|
+
* "synced_at": "2026-08-30T03:10:00.000Z"
|
|
69782
|
+
* },
|
|
69783
|
+
* "formulas": {
|
|
69784
|
+
* "acceptance": "mentores_2026_09_25",
|
|
69785
|
+
* "cierre": "cierre_2026_09_25",
|
|
69786
|
+
* "first_visit": "propuesta",
|
|
69787
|
+
* "second_visit": "propuesta",
|
|
69788
|
+
* "botados": "propuesta"
|
|
69789
|
+
* },
|
|
69790
|
+
* "headline": {
|
|
69791
|
+
* "collected_clp": 48500000,
|
|
69792
|
+
* "previous_collected_clp": 44100000,
|
|
69793
|
+
* "delta_pct": 10,
|
|
69794
|
+
* "previous_from": "2026-03-03",
|
|
69795
|
+
* "previous_to": "2026-05-31",
|
|
69796
|
+
* "rule": "Lo cobrado en el período: todos los pagos recibidos, sin los anulados. Se compara con el período anterior del mismo largo."
|
|
69797
|
+
* },
|
|
69798
|
+
* "acceptance": {
|
|
69799
|
+
* "presented": 420,
|
|
69800
|
+
* "accepted": 231,
|
|
69801
|
+
* "rate": 55,
|
|
69802
|
+
* "same_day": 118,
|
|
69803
|
+
* "later": 113,
|
|
69804
|
+
* "cita_only": 14,
|
|
69805
|
+
* "pending": 36,
|
|
69806
|
+
* "presented_clp": 142000000,
|
|
69807
|
+
* "accepted_clp": 71300000,
|
|
69808
|
+
* "rate_30d": 47.2,
|
|
69809
|
+
* "rate_60d": 53.8,
|
|
69810
|
+
* "formula": "mentores_2026_09_25",
|
|
69811
|
+
* "window_days": 60,
|
|
69812
|
+
* "long_window_days": 90,
|
|
69813
|
+
* "rule": "Presupuestos aceptados ÷ presupuestos presentados, cada presupuesto una vez."
|
|
69814
|
+
* },
|
|
69815
|
+
* "cierres": {
|
|
69816
|
+
* "count": 180,
|
|
69817
|
+
* "value_clp": 58900000,
|
|
69818
|
+
* "accepted_without_payment": 51,
|
|
69819
|
+
* "formula": "cierre_2026_09_25",
|
|
69820
|
+
* "rule": "Un cierre es el primer pago de un presupuesto aceptado."
|
|
69821
|
+
* },
|
|
69822
|
+
* "cohorts": [
|
|
69823
|
+
* {
|
|
69824
|
+
* "month": "2026-06",
|
|
69825
|
+
* "presented": 140,
|
|
69826
|
+
* "accepted": 80,
|
|
69827
|
+
* "rate": 57.1,
|
|
69828
|
+
* "same_day": 41,
|
|
69829
|
+
* "later": 39,
|
|
69830
|
+
* "cita_only": 2,
|
|
69831
|
+
* "pending": 0,
|
|
69832
|
+
* "presented_clp": 47000000,
|
|
69833
|
+
* "accepted_clp": 24800000,
|
|
69834
|
+
* "rate_30d": 49.3,
|
|
69835
|
+
* "rate_60d": 56.4,
|
|
69836
|
+
* "mature": true
|
|
69837
|
+
* }
|
|
69838
|
+
* ],
|
|
69839
|
+
* "by_professional": [
|
|
69840
|
+
* {
|
|
69841
|
+
* "professional_id": "0f3c2a9e-5b1d-4c7e-9a42-6d8e1f2b3c4d",
|
|
69842
|
+
* "professional_name": "Dra. Camila Soto",
|
|
69843
|
+
* "presented": 96,
|
|
69844
|
+
* "accepted": 61,
|
|
69845
|
+
* "rate": 63.5,
|
|
69846
|
+
* "same_day": 30,
|
|
69847
|
+
* "later": 31,
|
|
69848
|
+
* "cita_only": 3,
|
|
69849
|
+
* "pending": 8,
|
|
69850
|
+
* "presented_clp": 33400000,
|
|
69851
|
+
* "accepted_clp": 19900000,
|
|
69852
|
+
* "cierres": 47,
|
|
69853
|
+
* "cierres_clp": 15100000
|
|
69854
|
+
* }
|
|
69855
|
+
* ],
|
|
69856
|
+
* "unassigned_presented": 0,
|
|
69857
|
+
* "unassigned_cierres": 0,
|
|
69858
|
+
* "months": [
|
|
69859
|
+
* {
|
|
69860
|
+
* "month": "2026-06",
|
|
69861
|
+
* "accepted_clp": 24100000,
|
|
69862
|
+
* "produced_clp": 19700000,
|
|
69863
|
+
* "collected_clp": 16200000,
|
|
69864
|
+
* "cierres": 62,
|
|
69865
|
+
* "cierres_clp": 20300000
|
|
69866
|
+
* }
|
|
69867
|
+
* ],
|
|
69868
|
+
* "first_visit": {
|
|
69869
|
+
* "formula": "propuesta",
|
|
69870
|
+
* "patients": 210,
|
|
69871
|
+
* "paid": 97,
|
|
69872
|
+
* "rate": 46.2,
|
|
69873
|
+
* "rule": "Fórmula propuesta."
|
|
69874
|
+
* },
|
|
69875
|
+
* "second_visit": {
|
|
69876
|
+
* "formula": "propuesta",
|
|
69877
|
+
* "eligible": 113,
|
|
69878
|
+
* "converted": 29,
|
|
69879
|
+
* "rate": 25.7,
|
|
69880
|
+
* "rule": "Fórmula propuesta."
|
|
69881
|
+
* },
|
|
69882
|
+
* "botados": {
|
|
69883
|
+
* "unaccepted": {
|
|
69884
|
+
* "count": 88,
|
|
69885
|
+
* "clp": 31200000
|
|
69886
|
+
* },
|
|
69887
|
+
* "accepted_unscheduled": {
|
|
69888
|
+
* "count": 17,
|
|
69889
|
+
* "clp": 6400000
|
|
69890
|
+
* },
|
|
69891
|
+
* "mid_treatment_no_future_cita": {
|
|
69892
|
+
* "count": 23,
|
|
69893
|
+
* "clp": 9800000
|
|
69894
|
+
* },
|
|
69895
|
+
* "formula": "propuesta",
|
|
69896
|
+
* "basis": "live_last_6_months",
|
|
69897
|
+
* "total": {
|
|
69898
|
+
* "count": 128,
|
|
69899
|
+
* "clp": 47400000
|
|
69900
|
+
* },
|
|
69901
|
+
* "focus": "unaccepted",
|
|
69902
|
+
* "rule": "Fórmula propuesta."
|
|
69903
|
+
* },
|
|
69904
|
+
* "coverage": {
|
|
69905
|
+
* "plans_without_lines": 0,
|
|
69906
|
+
* "excluded_zero": 301,
|
|
69907
|
+
* "excluded_entry_only": 92
|
|
69908
|
+
* }
|
|
69909
|
+
* }
|
|
69910
|
+
* }
|
|
69911
|
+
*/
|
|
69912
|
+
"application/json": {
|
|
69913
|
+
data: components["schemas"]["ClinicComercialReport"];
|
|
69480
69914
|
};
|
|
69481
69915
|
};
|
|
69482
69916
|
};
|
|
@@ -76199,7 +76633,8 @@ interface paths {
|
|
|
76199
76633
|
* "display_name": "Garantía"
|
|
76200
76634
|
* }
|
|
76201
76635
|
* ],
|
|
76202
|
-
* "last_call": null
|
|
76636
|
+
* "last_call": null,
|
|
76637
|
+
* "handoff_urgent": false
|
|
76203
76638
|
* },
|
|
76204
76639
|
* {
|
|
76205
76640
|
* "id": "bbbbbbbb-0000-4000-8000-000000000002",
|
|
@@ -76335,7 +76770,8 @@ interface paths {
|
|
|
76335
76770
|
* "captured_at": "2026-09-22T10:41:12.004Z"
|
|
76336
76771
|
* },
|
|
76337
76772
|
* "tags": [],
|
|
76338
|
-
* "last_call": null
|
|
76773
|
+
* "last_call": null,
|
|
76774
|
+
* "handoff_urgent": false
|
|
76339
76775
|
* }
|
|
76340
76776
|
* ],
|
|
76341
76777
|
* "meta": {
|
|
@@ -76740,7 +77176,9 @@ interface paths {
|
|
|
76740
77176
|
*
|
|
76741
77177
|
* Also carries `ad_origin_nudge: 'connect_meta_ads' | null`, non-null ONLY when the caller holds `integrations:write`, the conversation came from a Meta ad (click-to-WhatsApp or an Instagram DM ad), and the workspace has no connected `meta_ads` integration. THIS ROUTE ONLY — deliberately absent from the list, where the predicate would be an N+1.
|
|
76742
77178
|
*
|
|
76743
|
-
* And `handoff_resolved_suggested: boolean` (#2968) — true only on an open/pending AI-handoff thread whose customer is still waiting on us AND Jev already read their own pending words as saying the matter is resolved (checked once per customer message, at the next handoff re-notify tick). The inbox reads this to offer a one-click close. THIS ROUTE ONLY, same N+1 reasoning as `ad_origin_nudge
|
|
77179
|
+
* And `handoff_resolved_suggested: boolean` (#2968) — true only on an open/pending AI-handoff thread whose customer is still waiting on us AND Jev already read their own pending words as saying the matter is resolved (checked once per customer message, at the next handoff re-notify tick). The inbox reads this to offer a one-click close. THIS ROUTE ONLY, same N+1 reasoning as `ad_origin_nudge` — unlike `handoff_urgent` below, this one was never worth a column since only the open thread needs it.
|
|
77180
|
+
*
|
|
77181
|
+
* `handoff_urgent: boolean` (#2969) is a plain `conversation` column, not a per-route annotation: true while an open/pending AI-handoff thread's customer is still waiting on us and Jev read their newest pending message as urgent (a clinic post-treatment complication, or an explicit same-day deadline) — kept in sync by the same classification that also tightens the re-notify cadence, and present on every conversation read, list included, because the inbox shows the flag on the conversation ROW too, not only its header.
|
|
76744
77182
|
*
|
|
76745
77183
|
* Carries `ad_origin` exactly as `GET /conversations` rows do.
|
|
76746
77184
|
*/
|
|
@@ -76883,6 +77321,7 @@ interface paths {
|
|
|
76883
77321
|
* }
|
|
76884
77322
|
* ],
|
|
76885
77323
|
* "last_call": null,
|
|
77324
|
+
* "handoff_urgent": false,
|
|
76886
77325
|
* "ad_origin_nudge": null,
|
|
76887
77326
|
* "handoff_resolved_suggested": false,
|
|
76888
77327
|
* "message": [
|
|
@@ -92624,75 +93063,982 @@ interface paths {
|
|
|
92624
93063
|
};
|
|
92625
93064
|
};
|
|
92626
93065
|
};
|
|
92627
|
-
put?: never;
|
|
92628
|
-
post?: never;
|
|
93066
|
+
put?: never;
|
|
93067
|
+
post?: never;
|
|
93068
|
+
delete?: never;
|
|
93069
|
+
options?: never;
|
|
93070
|
+
head?: never;
|
|
93071
|
+
patch?: never;
|
|
93072
|
+
trace?: never;
|
|
93073
|
+
};
|
|
93074
|
+
"/insights/generate-pdf": {
|
|
93075
|
+
parameters: {
|
|
93076
|
+
query?: never;
|
|
93077
|
+
header?: never;
|
|
93078
|
+
path?: never;
|
|
93079
|
+
cookie?: never;
|
|
93080
|
+
};
|
|
93081
|
+
get?: never;
|
|
93082
|
+
put?: never;
|
|
93083
|
+
/**
|
|
93084
|
+
* Render a report as a PDF
|
|
93085
|
+
* @description **The one endpoint on the tenant API that does not answer the `{ data }` envelope.** It replies with raw `application/pdf` bytes and a `Content-Disposition: attachment` header, so a client that pipes every response through the usual JSON parse will fail here. On an error it reverts to the JSON error envelope, which means the response content-type is what tells the two apart.
|
|
93086
|
+
*
|
|
93087
|
+
* Generation is SYNCHRONOUS: it queries the report, runs an LLM pass to write the narrative, then renders. The connection is held for all of that, there is no job id, and nothing is persisted — a client or proxy timeout loses the document with no way to retrieve it other than asking again. Treat a wide range as a slow request.
|
|
93088
|
+
*
|
|
93089
|
+
* The LLM pass degrades rather than fails: if the narrative cannot be generated you still get a 200 and a complete PDF, with a Spanish note in place of the executive summary and every raw figure intact. So a successful response does not by itself mean the analysis is there.
|
|
93090
|
+
*
|
|
93091
|
+
* `range.preset` is not a range selector — `from`/`to` alone decide the data. It is the window’s NAME: printed as the cover subtitle and passed into the summariser’s prompt, so a preset that disagrees with `from`/`to` mislabels the cover and misleads the narrative while the figures stay correct. Defaults to `custom`. Needs only `analytics:read`.
|
|
93092
|
+
*/
|
|
93093
|
+
post: {
|
|
93094
|
+
parameters: {
|
|
93095
|
+
query?: never;
|
|
93096
|
+
header?: {
|
|
93097
|
+
/** @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. */
|
|
93098
|
+
"Idempotency-Key"?: string;
|
|
93099
|
+
};
|
|
93100
|
+
path?: never;
|
|
93101
|
+
cookie?: never;
|
|
93102
|
+
};
|
|
93103
|
+
requestBody?: {
|
|
93104
|
+
content: {
|
|
93105
|
+
/**
|
|
93106
|
+
* @example {
|
|
93107
|
+
* "report": "conversations",
|
|
93108
|
+
* "window": {
|
|
93109
|
+
* "preset": "7d"
|
|
93110
|
+
* },
|
|
93111
|
+
* "range": {
|
|
93112
|
+
* "preset": "7d"
|
|
93113
|
+
* }
|
|
93114
|
+
* }
|
|
93115
|
+
*/
|
|
93116
|
+
"application/json": {
|
|
93117
|
+
/** @enum {string} */
|
|
93118
|
+
report_type: "overview" | "conversations" | "agents" | "ai_agents" | "bots" | "tags" | "channels" | "teams" | "leads" | "csat" | "sla" | "clinic_ocupacion" | "clinic_inasistencias" | "clinic_produccion" | "clinic_packs";
|
|
93119
|
+
range: {
|
|
93120
|
+
from: string;
|
|
93121
|
+
to: string;
|
|
93122
|
+
preset?: string;
|
|
93123
|
+
};
|
|
93124
|
+
};
|
|
93125
|
+
};
|
|
93126
|
+
};
|
|
93127
|
+
responses: {
|
|
93128
|
+
/** @description The rendered PDF as an attachment */
|
|
93129
|
+
200: {
|
|
93130
|
+
headers: {
|
|
93131
|
+
[name: string]: unknown;
|
|
93132
|
+
};
|
|
93133
|
+
content: {
|
|
93134
|
+
"application/pdf": string;
|
|
93135
|
+
};
|
|
93136
|
+
};
|
|
93137
|
+
/** @description Validation error */
|
|
93138
|
+
400: {
|
|
93139
|
+
headers: {
|
|
93140
|
+
[name: string]: unknown;
|
|
93141
|
+
};
|
|
93142
|
+
content: {
|
|
93143
|
+
"application/json": components["schemas"]["Error"];
|
|
93144
|
+
};
|
|
93145
|
+
};
|
|
93146
|
+
/** @description Unauthorized */
|
|
93147
|
+
401: {
|
|
93148
|
+
headers: {
|
|
93149
|
+
[name: string]: unknown;
|
|
93150
|
+
};
|
|
93151
|
+
content: {
|
|
93152
|
+
"application/json": components["schemas"]["Error"];
|
|
93153
|
+
};
|
|
93154
|
+
};
|
|
93155
|
+
/** @description Forbidden */
|
|
93156
|
+
403: {
|
|
93157
|
+
headers: {
|
|
93158
|
+
[name: string]: unknown;
|
|
93159
|
+
};
|
|
93160
|
+
content: {
|
|
93161
|
+
"application/json": components["schemas"]["Error"];
|
|
93162
|
+
};
|
|
93163
|
+
};
|
|
93164
|
+
/** @description Not found */
|
|
93165
|
+
404: {
|
|
93166
|
+
headers: {
|
|
93167
|
+
[name: string]: unknown;
|
|
93168
|
+
};
|
|
93169
|
+
content: {
|
|
93170
|
+
"application/json": components["schemas"]["Error"];
|
|
93171
|
+
};
|
|
93172
|
+
};
|
|
93173
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93174
|
+
409: {
|
|
93175
|
+
headers: {
|
|
93176
|
+
[name: string]: unknown;
|
|
93177
|
+
};
|
|
93178
|
+
content: {
|
|
93179
|
+
"application/json": components["schemas"]["Error"];
|
|
93180
|
+
};
|
|
93181
|
+
};
|
|
93182
|
+
/** @description Rate limited */
|
|
93183
|
+
429: {
|
|
93184
|
+
headers: {
|
|
93185
|
+
[name: string]: unknown;
|
|
93186
|
+
};
|
|
93187
|
+
content: {
|
|
93188
|
+
"application/json": components["schemas"]["Error"];
|
|
93189
|
+
};
|
|
93190
|
+
};
|
|
93191
|
+
};
|
|
93192
|
+
};
|
|
93193
|
+
delete?: never;
|
|
93194
|
+
options?: never;
|
|
93195
|
+
head?: never;
|
|
93196
|
+
patch?: never;
|
|
93197
|
+
trace?: never;
|
|
93198
|
+
};
|
|
93199
|
+
"/insights/schedules": {
|
|
93200
|
+
parameters: {
|
|
93201
|
+
query?: never;
|
|
93202
|
+
header?: never;
|
|
93203
|
+
path?: never;
|
|
93204
|
+
cookie?: never;
|
|
93205
|
+
};
|
|
93206
|
+
/**
|
|
93207
|
+
* List report schedules
|
|
93208
|
+
* @description The standing subscriptions that mail a rendered report out on a cadence. Unpaginated, and with no `meta.total` — this list is small by construction.
|
|
93209
|
+
*/
|
|
93210
|
+
get: {
|
|
93211
|
+
parameters: {
|
|
93212
|
+
query?: never;
|
|
93213
|
+
header?: never;
|
|
93214
|
+
path?: never;
|
|
93215
|
+
cookie?: never;
|
|
93216
|
+
};
|
|
93217
|
+
requestBody?: never;
|
|
93218
|
+
responses: {
|
|
93219
|
+
/** @description Report schedules */
|
|
93220
|
+
200: {
|
|
93221
|
+
headers: {
|
|
93222
|
+
[name: string]: unknown;
|
|
93223
|
+
};
|
|
93224
|
+
content: {
|
|
93225
|
+
/**
|
|
93226
|
+
* @example {
|
|
93227
|
+
* "data": [
|
|
93228
|
+
* {
|
|
93229
|
+
* "id": "cccccccc-2000-4000-8000-000000000001",
|
|
93230
|
+
* "report_type": "conversations",
|
|
93231
|
+
* "range_preset": "7d",
|
|
93232
|
+
* "cadence": "weekly",
|
|
93233
|
+
* "recipients": [
|
|
93234
|
+
* "gerencia@midealer.cl"
|
|
93235
|
+
* ],
|
|
93236
|
+
* "next_run_at": "2026-09-29T09:00:00.000Z",
|
|
93237
|
+
* "enabled": true
|
|
93238
|
+
* }
|
|
93239
|
+
* ]
|
|
93240
|
+
* }
|
|
93241
|
+
*/
|
|
93242
|
+
"application/json": {
|
|
93243
|
+
data?: unknown;
|
|
93244
|
+
meta?: {
|
|
93245
|
+
[key: string]: unknown;
|
|
93246
|
+
};
|
|
93247
|
+
};
|
|
93248
|
+
};
|
|
93249
|
+
};
|
|
93250
|
+
/** @description Validation error */
|
|
93251
|
+
400: {
|
|
93252
|
+
headers: {
|
|
93253
|
+
[name: string]: unknown;
|
|
93254
|
+
};
|
|
93255
|
+
content: {
|
|
93256
|
+
"application/json": components["schemas"]["Error"];
|
|
93257
|
+
};
|
|
93258
|
+
};
|
|
93259
|
+
/** @description Unauthorized */
|
|
93260
|
+
401: {
|
|
93261
|
+
headers: {
|
|
93262
|
+
[name: string]: unknown;
|
|
93263
|
+
};
|
|
93264
|
+
content: {
|
|
93265
|
+
"application/json": components["schemas"]["Error"];
|
|
93266
|
+
};
|
|
93267
|
+
};
|
|
93268
|
+
/** @description Forbidden */
|
|
93269
|
+
403: {
|
|
93270
|
+
headers: {
|
|
93271
|
+
[name: string]: unknown;
|
|
93272
|
+
};
|
|
93273
|
+
content: {
|
|
93274
|
+
"application/json": components["schemas"]["Error"];
|
|
93275
|
+
};
|
|
93276
|
+
};
|
|
93277
|
+
/** @description Not found */
|
|
93278
|
+
404: {
|
|
93279
|
+
headers: {
|
|
93280
|
+
[name: string]: unknown;
|
|
93281
|
+
};
|
|
93282
|
+
content: {
|
|
93283
|
+
"application/json": components["schemas"]["Error"];
|
|
93284
|
+
};
|
|
93285
|
+
};
|
|
93286
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93287
|
+
409: {
|
|
93288
|
+
headers: {
|
|
93289
|
+
[name: string]: unknown;
|
|
93290
|
+
};
|
|
93291
|
+
content: {
|
|
93292
|
+
"application/json": components["schemas"]["Error"];
|
|
93293
|
+
};
|
|
93294
|
+
};
|
|
93295
|
+
/** @description Rate limited */
|
|
93296
|
+
429: {
|
|
93297
|
+
headers: {
|
|
93298
|
+
[name: string]: unknown;
|
|
93299
|
+
};
|
|
93300
|
+
content: {
|
|
93301
|
+
"application/json": components["schemas"]["Error"];
|
|
93302
|
+
};
|
|
93303
|
+
};
|
|
93304
|
+
};
|
|
93305
|
+
};
|
|
93306
|
+
put?: never;
|
|
93307
|
+
post?: never;
|
|
93308
|
+
delete?: never;
|
|
93309
|
+
options?: never;
|
|
93310
|
+
head?: never;
|
|
93311
|
+
patch?: never;
|
|
93312
|
+
trace?: never;
|
|
93313
|
+
};
|
|
93314
|
+
"/integrations/meta-ads": {
|
|
93315
|
+
parameters: {
|
|
93316
|
+
query?: never;
|
|
93317
|
+
header?: never;
|
|
93318
|
+
path?: never;
|
|
93319
|
+
cookie?: never;
|
|
93320
|
+
};
|
|
93321
|
+
/**
|
|
93322
|
+
* Read the workspace’s Meta Ads connection
|
|
93323
|
+
* @description The tenant’s single Meta Ads row, or `null` when it has never started a connect. A placeholder object with `status: "disconnected"` is deliberately NOT returned in its place: "never connected" and "was connected and is not any more" are different states and the card says different things about them.
|
|
93324
|
+
*
|
|
93325
|
+
* `handoff` is populated only while `status` is `pending` and `candidates` only while it is `pending_selection` — a spent consent URL would render a button leading to a dead page.
|
|
93326
|
+
*
|
|
93327
|
+
* Requires `integrations:read` or `ads:read` (owner, admin and the Marketing role); a `supervisor` or `agent` gets 403 here and never sees the card. The writes need `integrations:write` or `ads:write`.
|
|
93328
|
+
*/
|
|
93329
|
+
get: {
|
|
93330
|
+
parameters: {
|
|
93331
|
+
query?: never;
|
|
93332
|
+
header?: never;
|
|
93333
|
+
path?: never;
|
|
93334
|
+
cookie?: never;
|
|
93335
|
+
};
|
|
93336
|
+
requestBody?: never;
|
|
93337
|
+
responses: {
|
|
93338
|
+
/** @description The Meta Ads integration, or `null` */
|
|
93339
|
+
200: {
|
|
93340
|
+
headers: {
|
|
93341
|
+
[name: string]: unknown;
|
|
93342
|
+
};
|
|
93343
|
+
content: {
|
|
93344
|
+
/**
|
|
93345
|
+
* @example {
|
|
93346
|
+
* "data": null
|
|
93347
|
+
* }
|
|
93348
|
+
*/
|
|
93349
|
+
"application/json": {
|
|
93350
|
+
data: components["schemas"]["MetaAdsIntegration"];
|
|
93351
|
+
};
|
|
93352
|
+
};
|
|
93353
|
+
};
|
|
93354
|
+
/** @description Validation error */
|
|
93355
|
+
400: {
|
|
93356
|
+
headers: {
|
|
93357
|
+
[name: string]: unknown;
|
|
93358
|
+
};
|
|
93359
|
+
content: {
|
|
93360
|
+
"application/json": components["schemas"]["Error"];
|
|
93361
|
+
};
|
|
93362
|
+
};
|
|
93363
|
+
/** @description Unauthorized */
|
|
93364
|
+
401: {
|
|
93365
|
+
headers: {
|
|
93366
|
+
[name: string]: unknown;
|
|
93367
|
+
};
|
|
93368
|
+
content: {
|
|
93369
|
+
"application/json": components["schemas"]["Error"];
|
|
93370
|
+
};
|
|
93371
|
+
};
|
|
93372
|
+
/** @description Forbidden */
|
|
93373
|
+
403: {
|
|
93374
|
+
headers: {
|
|
93375
|
+
[name: string]: unknown;
|
|
93376
|
+
};
|
|
93377
|
+
content: {
|
|
93378
|
+
"application/json": components["schemas"]["Error"];
|
|
93379
|
+
};
|
|
93380
|
+
};
|
|
93381
|
+
/** @description Not found */
|
|
93382
|
+
404: {
|
|
93383
|
+
headers: {
|
|
93384
|
+
[name: string]: unknown;
|
|
93385
|
+
};
|
|
93386
|
+
content: {
|
|
93387
|
+
"application/json": components["schemas"]["Error"];
|
|
93388
|
+
};
|
|
93389
|
+
};
|
|
93390
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93391
|
+
409: {
|
|
93392
|
+
headers: {
|
|
93393
|
+
[name: string]: unknown;
|
|
93394
|
+
};
|
|
93395
|
+
content: {
|
|
93396
|
+
"application/json": components["schemas"]["Error"];
|
|
93397
|
+
};
|
|
93398
|
+
};
|
|
93399
|
+
/** @description Rate limited */
|
|
93400
|
+
429: {
|
|
93401
|
+
headers: {
|
|
93402
|
+
[name: string]: unknown;
|
|
93403
|
+
};
|
|
93404
|
+
content: {
|
|
93405
|
+
"application/json": components["schemas"]["Error"];
|
|
93406
|
+
};
|
|
93407
|
+
};
|
|
93408
|
+
};
|
|
93409
|
+
};
|
|
93410
|
+
put?: never;
|
|
93411
|
+
post?: never;
|
|
93412
|
+
delete?: never;
|
|
93413
|
+
options?: never;
|
|
93414
|
+
head?: never;
|
|
93415
|
+
patch?: never;
|
|
93416
|
+
trace?: never;
|
|
93417
|
+
};
|
|
93418
|
+
"/integrations/meta-ads/connect": {
|
|
93419
|
+
parameters: {
|
|
93420
|
+
query?: never;
|
|
93421
|
+
header?: never;
|
|
93422
|
+
path?: never;
|
|
93423
|
+
cookie?: never;
|
|
93424
|
+
};
|
|
93425
|
+
get?: never;
|
|
93426
|
+
put?: never;
|
|
93427
|
+
/**
|
|
93428
|
+
* Start a Meta Ads connect and get the consent URL
|
|
93429
|
+
* @description Mints the connection provider’s **connect hand-off** for `meta_ads` and answers the session-less consent URL to redirect the WHOLE PAGE to. It is not an iframe target: Meta’s own consent dialog renders inside it.
|
|
93430
|
+
*
|
|
93431
|
+
* `return_to` must be an absolute URL on the app’s own origin. The backend appends `meta_ads=return` and a short opaque `state`, preserving any query the URL already carried, and passes the result to the provider as `return_url`. An origin that is not the app’s is a 400 here rather than a silent substitution — the provider itself only checks the origin when the human CLICKS, where it surfaces as a failed hand-off (`result.reason: origin_not_allowed`) after the dealer has already walked through a consent screen for nothing.
|
|
93432
|
+
*
|
|
93433
|
+
* **A second click reuses the live hand-off.** The provider’s URL is single-use and 45-minute-lived, and minting twice yields two hand-offs rather than an error, so a dealer who clicks, gets distracted and clicks again gets the SAME `url` and `handoff_id` back until it expires.
|
|
93434
|
+
*
|
|
93435
|
+
* Before anything is minted, the tenant’s attribution profile and its delegated key are ensured (ADR 0099). This rail never uses a platform-wide provider key.
|
|
93436
|
+
*/
|
|
93437
|
+
post: {
|
|
93438
|
+
parameters: {
|
|
93439
|
+
query?: never;
|
|
93440
|
+
header?: {
|
|
93441
|
+
/** @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. */
|
|
93442
|
+
"Idempotency-Key"?: string;
|
|
93443
|
+
};
|
|
93444
|
+
path?: never;
|
|
93445
|
+
cookie?: never;
|
|
93446
|
+
};
|
|
93447
|
+
requestBody?: {
|
|
93448
|
+
content: {
|
|
93449
|
+
/**
|
|
93450
|
+
* @example {
|
|
93451
|
+
* "return_to": "https://app.vitrinadev.com/settings/integraciones?meta_ads=return"
|
|
93452
|
+
* }
|
|
93453
|
+
*/
|
|
93454
|
+
"application/json": components["schemas"]["MetaAdsConnectBody"];
|
|
93455
|
+
};
|
|
93456
|
+
};
|
|
93457
|
+
responses: {
|
|
93458
|
+
/** @description The consent URL, its hand-off id, and its expiry */
|
|
93459
|
+
200: {
|
|
93460
|
+
headers: {
|
|
93461
|
+
[name: string]: unknown;
|
|
93462
|
+
};
|
|
93463
|
+
content: {
|
|
93464
|
+
/**
|
|
93465
|
+
* @example {
|
|
93466
|
+
* "data": {
|
|
93467
|
+
* "url": "https://consent.example.com/connect/meta-ads/ho_4d8f2a91c6b3",
|
|
93468
|
+
* "handoff_id": "ho_4d8f2a91c6b3",
|
|
93469
|
+
* "expires_at": "2026-09-23T15:45:00.000Z"
|
|
93470
|
+
* }
|
|
93471
|
+
* }
|
|
93472
|
+
*/
|
|
93473
|
+
"application/json": {
|
|
93474
|
+
data: components["schemas"]["MetaAdsConnectResult"];
|
|
93475
|
+
};
|
|
93476
|
+
};
|
|
93477
|
+
};
|
|
93478
|
+
/** @description Validation error */
|
|
93479
|
+
400: {
|
|
93480
|
+
headers: {
|
|
93481
|
+
[name: string]: unknown;
|
|
93482
|
+
};
|
|
93483
|
+
content: {
|
|
93484
|
+
"application/json": components["schemas"]["Error"];
|
|
93485
|
+
};
|
|
93486
|
+
};
|
|
93487
|
+
/** @description Unauthorized */
|
|
93488
|
+
401: {
|
|
93489
|
+
headers: {
|
|
93490
|
+
[name: string]: unknown;
|
|
93491
|
+
};
|
|
93492
|
+
content: {
|
|
93493
|
+
"application/json": components["schemas"]["Error"];
|
|
93494
|
+
};
|
|
93495
|
+
};
|
|
93496
|
+
/** @description Forbidden */
|
|
93497
|
+
403: {
|
|
93498
|
+
headers: {
|
|
93499
|
+
[name: string]: unknown;
|
|
93500
|
+
};
|
|
93501
|
+
content: {
|
|
93502
|
+
"application/json": components["schemas"]["Error"];
|
|
93503
|
+
};
|
|
93504
|
+
};
|
|
93505
|
+
/** @description Not found */
|
|
93506
|
+
404: {
|
|
93507
|
+
headers: {
|
|
93508
|
+
[name: string]: unknown;
|
|
93509
|
+
};
|
|
93510
|
+
content: {
|
|
93511
|
+
"application/json": components["schemas"]["Error"];
|
|
93512
|
+
};
|
|
93513
|
+
};
|
|
93514
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93515
|
+
409: {
|
|
93516
|
+
headers: {
|
|
93517
|
+
[name: string]: unknown;
|
|
93518
|
+
};
|
|
93519
|
+
content: {
|
|
93520
|
+
"application/json": components["schemas"]["Error"];
|
|
93521
|
+
};
|
|
93522
|
+
};
|
|
93523
|
+
/** @description Rate limited */
|
|
93524
|
+
429: {
|
|
93525
|
+
headers: {
|
|
93526
|
+
[name: string]: unknown;
|
|
93527
|
+
};
|
|
93528
|
+
content: {
|
|
93529
|
+
"application/json": components["schemas"]["Error"];
|
|
93530
|
+
};
|
|
93531
|
+
};
|
|
93532
|
+
};
|
|
93533
|
+
};
|
|
93534
|
+
delete?: never;
|
|
93535
|
+
options?: never;
|
|
93536
|
+
head?: never;
|
|
93537
|
+
patch?: never;
|
|
93538
|
+
trace?: never;
|
|
93539
|
+
};
|
|
93540
|
+
"/integrations/meta-ads/return": {
|
|
93541
|
+
parameters: {
|
|
93542
|
+
query?: never;
|
|
93543
|
+
header?: never;
|
|
93544
|
+
path?: never;
|
|
93545
|
+
cookie?: never;
|
|
93546
|
+
};
|
|
93547
|
+
get?: never;
|
|
93548
|
+
put?: never;
|
|
93549
|
+
/**
|
|
93550
|
+
* Settle a Meta Ads connect after the dealer comes back
|
|
93551
|
+
* @description Reads the hand-off ONCE and settles the row:
|
|
93552
|
+
*
|
|
93553
|
+
* * `completed` with a connection id → the connection is read back from the provider and the row becomes `connected`, carrying the ad account’s name, id, currency, timezone and whether the platform has ever delivered spend.
|
|
93554
|
+
* * `completed` with a pending selection → the row becomes `pending_selection` and carries the candidates the picker renders. **A consent that resolved to exactly one account never reaches this branch** — the provider finalizes it in its own callback, which is why there is no auto-finalize step on this side.
|
|
93555
|
+
* * `expired` / `cancelled` / `failed` → the row becomes `error` with a retryable `reason` of `handoff_<status>`. The recovery is identical for all three: mint a fresh hand-off.
|
|
93556
|
+
* * still `pending` → nothing is settled and the row comes back unchanged.
|
|
93557
|
+
*
|
|
93558
|
+
* **Neither field is required.** The hand-off id only exists in the RESPONSE to the mint while `return_url` is an argument to that same mint, so the return URL structurally cannot carry it — it carries `meta_ads=return` and the opaque `state` instead. Send `handoff_id` if you kept it, `state` if you read it off the URL, or an empty body, in which case the backend settles the row’s own pending hand-off (unambiguous: a tenant has at most one).
|
|
93559
|
+
*
|
|
93560
|
+
* Safe to repeat — a settled hand-off stays readable at the provider, so a re-post on a refresh re-derives the same state.
|
|
93561
|
+
*
|
|
93562
|
+
* 409 `handoff_mismatch` when the id or state presented does not name the hand-off this tenant’s row is waiting on, and for a tenant with no connect in flight at all (the two are deliberately the same answer).
|
|
93563
|
+
*
|
|
93564
|
+
* 502 `UPSTREAM_ERROR` when the provider could not be read; the row is left unchanged and the call is safe to repeat.
|
|
93565
|
+
*/
|
|
93566
|
+
post: {
|
|
93567
|
+
parameters: {
|
|
93568
|
+
query?: never;
|
|
93569
|
+
header?: {
|
|
93570
|
+
/** @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. */
|
|
93571
|
+
"Idempotency-Key"?: string;
|
|
93572
|
+
};
|
|
93573
|
+
path?: never;
|
|
93574
|
+
cookie?: never;
|
|
93575
|
+
};
|
|
93576
|
+
requestBody?: {
|
|
93577
|
+
content: {
|
|
93578
|
+
/**
|
|
93579
|
+
* @example {
|
|
93580
|
+
* "state": "9f3a2d7c8b1e4a2f"
|
|
93581
|
+
* }
|
|
93582
|
+
*/
|
|
93583
|
+
"application/json": components["schemas"]["MetaAdsReturnBody"];
|
|
93584
|
+
};
|
|
93585
|
+
};
|
|
93586
|
+
responses: {
|
|
93587
|
+
/** @description The settled integration */
|
|
93588
|
+
200: {
|
|
93589
|
+
headers: {
|
|
93590
|
+
[name: string]: unknown;
|
|
93591
|
+
};
|
|
93592
|
+
content: {
|
|
93593
|
+
/**
|
|
93594
|
+
* @example {
|
|
93595
|
+
* "data": {
|
|
93596
|
+
* "id": "22222222-2222-4222-8222-222222222222",
|
|
93597
|
+
* "provider": "meta_ads",
|
|
93598
|
+
* "status": "connected",
|
|
93599
|
+
* "account_label": "Cuenta Meta Ads",
|
|
93600
|
+
* "connected_at": "2026-09-23T15:04:00.000Z",
|
|
93601
|
+
* "disconnected_at": null,
|
|
93602
|
+
* "account": {
|
|
93603
|
+
* "external_account_id": "act_1234567890",
|
|
93604
|
+
* "name": "Automotora Ejemplo",
|
|
93605
|
+
* "currency": "CLP",
|
|
93606
|
+
* "timezone": "America/Santiago",
|
|
93607
|
+
* "delivers_spend": true,
|
|
93608
|
+
* "provider_connection_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
93609
|
+
* "atribu_connection_id": "c0c0c0c0-0000-4000-8000-000000000001"
|
|
93610
|
+
* },
|
|
93611
|
+
* "error": null,
|
|
93612
|
+
* "handoff": null,
|
|
93613
|
+
* "candidates": null,
|
|
93614
|
+
* "updated_at": "2026-09-23T15:04:00.000Z"
|
|
93615
|
+
* }
|
|
93616
|
+
* }
|
|
93617
|
+
*/
|
|
93618
|
+
"application/json": {
|
|
93619
|
+
data: components["schemas"]["MetaAdsIntegration"] & Record<string, never>;
|
|
93620
|
+
};
|
|
93621
|
+
};
|
|
93622
|
+
};
|
|
93623
|
+
/** @description Validation error */
|
|
93624
|
+
400: {
|
|
93625
|
+
headers: {
|
|
93626
|
+
[name: string]: unknown;
|
|
93627
|
+
};
|
|
93628
|
+
content: {
|
|
93629
|
+
"application/json": components["schemas"]["Error"];
|
|
93630
|
+
};
|
|
93631
|
+
};
|
|
93632
|
+
/** @description Unauthorized */
|
|
93633
|
+
401: {
|
|
93634
|
+
headers: {
|
|
93635
|
+
[name: string]: unknown;
|
|
93636
|
+
};
|
|
93637
|
+
content: {
|
|
93638
|
+
"application/json": components["schemas"]["Error"];
|
|
93639
|
+
};
|
|
93640
|
+
};
|
|
93641
|
+
/** @description Forbidden */
|
|
93642
|
+
403: {
|
|
93643
|
+
headers: {
|
|
93644
|
+
[name: string]: unknown;
|
|
93645
|
+
};
|
|
93646
|
+
content: {
|
|
93647
|
+
"application/json": components["schemas"]["Error"];
|
|
93648
|
+
};
|
|
93649
|
+
};
|
|
93650
|
+
/** @description Not found */
|
|
93651
|
+
404: {
|
|
93652
|
+
headers: {
|
|
93653
|
+
[name: string]: unknown;
|
|
93654
|
+
};
|
|
93655
|
+
content: {
|
|
93656
|
+
"application/json": components["schemas"]["Error"];
|
|
93657
|
+
};
|
|
93658
|
+
};
|
|
93659
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93660
|
+
409: {
|
|
93661
|
+
headers: {
|
|
93662
|
+
[name: string]: unknown;
|
|
93663
|
+
};
|
|
93664
|
+
content: {
|
|
93665
|
+
"application/json": components["schemas"]["Error"];
|
|
93666
|
+
};
|
|
93667
|
+
};
|
|
93668
|
+
/** @description Rate limited */
|
|
93669
|
+
429: {
|
|
93670
|
+
headers: {
|
|
93671
|
+
[name: string]: unknown;
|
|
93672
|
+
};
|
|
93673
|
+
content: {
|
|
93674
|
+
"application/json": components["schemas"]["Error"];
|
|
93675
|
+
};
|
|
93676
|
+
};
|
|
93677
|
+
};
|
|
93678
|
+
};
|
|
93679
|
+
delete?: never;
|
|
93680
|
+
options?: never;
|
|
93681
|
+
head?: never;
|
|
93682
|
+
patch?: never;
|
|
93683
|
+
trace?: never;
|
|
93684
|
+
};
|
|
93685
|
+
"/integrations/meta-ads/disconnect": {
|
|
93686
|
+
parameters: {
|
|
93687
|
+
query?: never;
|
|
93688
|
+
header?: never;
|
|
93689
|
+
path?: never;
|
|
93690
|
+
cookie?: never;
|
|
93691
|
+
};
|
|
93692
|
+
get?: never;
|
|
93693
|
+
put?: never;
|
|
93694
|
+
/**
|
|
93695
|
+
* Disconnect the workspace’s Meta Ads ad account
|
|
93696
|
+
* @description Calls the provider’s disconnect for the connection on the delegated key and settles the row `disconnected`, keeping its history: `account_label` and `connected_at` stay, and `config.last_account` remembers which account this was so the card can still name it. Reconnecting afterwards is a plain new `/connect` — it mints a fresh hand-off. A tenant must always be able to walk away from a connection it made.
|
|
93697
|
+
*
|
|
93698
|
+
* A row with nothing at the provider to revoke — `pending` / `pending_selection` with no connection — is cancelled LOCALLY: no provider call, the row moves straight to `disconnected`, and the pending hand-off simply expires on its own (the provider has no endpoint to cancel one early). A row already `disconnected` answers 200 unchanged (idempotent).
|
|
93699
|
+
*
|
|
93700
|
+
* 409 `sync_in_flight` when the provider is mid-sync on the connection — the row is left exactly as it was; the whole recovery is trying again in a few minutes. 502 `disconnect_refused` when the provider’s own 403 says the delegated key is no longer good for this connection — also left unchanged. A 404 from the provider (the connection is already gone there) is treated as success: the state this call exists to ensure already holds.
|
|
93701
|
+
*/
|
|
93702
|
+
post: {
|
|
93703
|
+
parameters: {
|
|
93704
|
+
query?: never;
|
|
93705
|
+
header?: {
|
|
93706
|
+
/** @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. */
|
|
93707
|
+
"Idempotency-Key"?: string;
|
|
93708
|
+
};
|
|
93709
|
+
path?: never;
|
|
93710
|
+
cookie?: never;
|
|
93711
|
+
};
|
|
93712
|
+
requestBody?: never;
|
|
93713
|
+
responses: {
|
|
93714
|
+
/** @description The disconnected integration */
|
|
93715
|
+
200: {
|
|
93716
|
+
headers: {
|
|
93717
|
+
[name: string]: unknown;
|
|
93718
|
+
};
|
|
93719
|
+
content: {
|
|
93720
|
+
/**
|
|
93721
|
+
* @example {
|
|
93722
|
+
* "data": {
|
|
93723
|
+
* "id": "22222222-2222-4222-8222-222222222222",
|
|
93724
|
+
* "provider": "meta_ads",
|
|
93725
|
+
* "status": "disconnected",
|
|
93726
|
+
* "account_label": "Cuenta Meta Ads",
|
|
93727
|
+
* "connected_at": "2026-09-20T12:00:00.000Z",
|
|
93728
|
+
* "disconnected_at": "2026-09-23T15:10:00.000Z",
|
|
93729
|
+
* "account": null,
|
|
93730
|
+
* "error": null,
|
|
93731
|
+
* "handoff": null,
|
|
93732
|
+
* "candidates": null,
|
|
93733
|
+
* "updated_at": "2026-09-23T15:10:00.000Z"
|
|
93734
|
+
* }
|
|
93735
|
+
* }
|
|
93736
|
+
*/
|
|
93737
|
+
"application/json": {
|
|
93738
|
+
data: components["schemas"]["MetaAdsIntegration"] & Record<string, never>;
|
|
93739
|
+
};
|
|
93740
|
+
};
|
|
93741
|
+
};
|
|
93742
|
+
/** @description Validation error */
|
|
93743
|
+
400: {
|
|
93744
|
+
headers: {
|
|
93745
|
+
[name: string]: unknown;
|
|
93746
|
+
};
|
|
93747
|
+
content: {
|
|
93748
|
+
"application/json": components["schemas"]["Error"];
|
|
93749
|
+
};
|
|
93750
|
+
};
|
|
93751
|
+
/** @description Unauthorized */
|
|
93752
|
+
401: {
|
|
93753
|
+
headers: {
|
|
93754
|
+
[name: string]: unknown;
|
|
93755
|
+
};
|
|
93756
|
+
content: {
|
|
93757
|
+
"application/json": components["schemas"]["Error"];
|
|
93758
|
+
};
|
|
93759
|
+
};
|
|
93760
|
+
/** @description Forbidden */
|
|
93761
|
+
403: {
|
|
93762
|
+
headers: {
|
|
93763
|
+
[name: string]: unknown;
|
|
93764
|
+
};
|
|
93765
|
+
content: {
|
|
93766
|
+
"application/json": components["schemas"]["Error"];
|
|
93767
|
+
};
|
|
93768
|
+
};
|
|
93769
|
+
/** @description Not found */
|
|
93770
|
+
404: {
|
|
93771
|
+
headers: {
|
|
93772
|
+
[name: string]: unknown;
|
|
93773
|
+
};
|
|
93774
|
+
content: {
|
|
93775
|
+
"application/json": components["schemas"]["Error"];
|
|
93776
|
+
};
|
|
93777
|
+
};
|
|
93778
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93779
|
+
409: {
|
|
93780
|
+
headers: {
|
|
93781
|
+
[name: string]: unknown;
|
|
93782
|
+
};
|
|
93783
|
+
content: {
|
|
93784
|
+
"application/json": components["schemas"]["Error"];
|
|
93785
|
+
};
|
|
93786
|
+
};
|
|
93787
|
+
/** @description Rate limited */
|
|
93788
|
+
429: {
|
|
93789
|
+
headers: {
|
|
93790
|
+
[name: string]: unknown;
|
|
93791
|
+
};
|
|
93792
|
+
content: {
|
|
93793
|
+
"application/json": components["schemas"]["Error"];
|
|
93794
|
+
};
|
|
93795
|
+
};
|
|
93796
|
+
};
|
|
93797
|
+
};
|
|
93798
|
+
delete?: never;
|
|
93799
|
+
options?: never;
|
|
93800
|
+
head?: never;
|
|
93801
|
+
patch?: never;
|
|
93802
|
+
trace?: never;
|
|
93803
|
+
};
|
|
93804
|
+
"/integrations/meta-ads/finalize": {
|
|
93805
|
+
parameters: {
|
|
93806
|
+
query?: never;
|
|
93807
|
+
header?: never;
|
|
93808
|
+
path?: never;
|
|
93809
|
+
cookie?: never;
|
|
93810
|
+
};
|
|
93811
|
+
get?: never;
|
|
93812
|
+
put?: never;
|
|
93813
|
+
/**
|
|
93814
|
+
* Finalize a Meta Ads pending selection with a chosen candidate
|
|
93815
|
+
* @description Only meaningful while `status` is `pending_selection`. Calls the provider’s finalize on the parked provider token with the chosen `candidate_id` — a `MetaAdsCandidate.candidate_id` from the SAME row’s `candidates`, sent back verbatim — reads the resulting connection back (the provider’s Meta Ads connections read) and runs it through the same settle path `/return` uses, so the row reads identically whichever produced it: `connected`, with `account` populated.
|
|
93816
|
+
*
|
|
93817
|
+
* **Retrying the same `candidate_id` is safe** and answers 200 with the current row — the provider’s `already_finalized: true` on its own idempotent replay, reapplied through the same write path a fresh finalize uses.
|
|
93818
|
+
*
|
|
93819
|
+
* **A DIFFERENT `candidate_id`** after the provider’s parked token already finalized a choice is 409 `start_again` (the row moves to `error`, `reason: selection_conflict`, retryable) — switching accounts needs a fresh connect, there is no token left to retarget.
|
|
93820
|
+
*
|
|
93821
|
+
* **The picker’s 60-minute parked token already gone** (elapsed, or never existed for this profile) is 410 `reconnect` (the row moves to `error`, `reason: selection_expired`, retryable).
|
|
93822
|
+
*
|
|
93823
|
+
* **The row is not `pending_selection`** — nothing started, already connected, or already in `error` — is 409 `handoff_mismatch`, checked before the provider is ever called.
|
|
93824
|
+
*
|
|
93825
|
+
* 502 `UPSTREAM_ERROR` when the provider could not be read; the row is left unchanged and the call is safe to repeat.
|
|
93826
|
+
*/
|
|
93827
|
+
post: {
|
|
93828
|
+
parameters: {
|
|
93829
|
+
query?: never;
|
|
93830
|
+
header?: {
|
|
93831
|
+
/** @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. */
|
|
93832
|
+
"Idempotency-Key"?: string;
|
|
93833
|
+
};
|
|
93834
|
+
path?: never;
|
|
93835
|
+
cookie?: never;
|
|
93836
|
+
};
|
|
93837
|
+
requestBody?: {
|
|
93838
|
+
content: {
|
|
93839
|
+
/**
|
|
93840
|
+
* @example {
|
|
93841
|
+
* "candidate_id": "cnd_7b1f0a4e9d2c"
|
|
93842
|
+
* }
|
|
93843
|
+
*/
|
|
93844
|
+
"application/json": components["schemas"]["MetaAdsFinalizeBody"];
|
|
93845
|
+
};
|
|
93846
|
+
};
|
|
93847
|
+
responses: {
|
|
93848
|
+
/** @description The finalized integration, now `connected` */
|
|
93849
|
+
200: {
|
|
93850
|
+
headers: {
|
|
93851
|
+
[name: string]: unknown;
|
|
93852
|
+
};
|
|
93853
|
+
content: {
|
|
93854
|
+
/**
|
|
93855
|
+
* @example {
|
|
93856
|
+
* "data": {
|
|
93857
|
+
* "id": "22222222-2222-4222-8222-222222222222",
|
|
93858
|
+
* "provider": "meta_ads",
|
|
93859
|
+
* "status": "connected",
|
|
93860
|
+
* "account_label": "Cuenta Meta Ads",
|
|
93861
|
+
* "connected_at": "2026-09-23T15:04:00.000Z",
|
|
93862
|
+
* "disconnected_at": null,
|
|
93863
|
+
* "account": {
|
|
93864
|
+
* "external_account_id": "act_1234567890",
|
|
93865
|
+
* "name": "Automotora Ejemplo",
|
|
93866
|
+
* "currency": "CLP",
|
|
93867
|
+
* "timezone": "America/Santiago",
|
|
93868
|
+
* "delivers_spend": true,
|
|
93869
|
+
* "provider_connection_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
93870
|
+
* "atribu_connection_id": "c0c0c0c0-0000-4000-8000-000000000001"
|
|
93871
|
+
* },
|
|
93872
|
+
* "error": null,
|
|
93873
|
+
* "handoff": null,
|
|
93874
|
+
* "candidates": null,
|
|
93875
|
+
* "updated_at": "2026-09-23T15:04:00.000Z"
|
|
93876
|
+
* }
|
|
93877
|
+
* }
|
|
93878
|
+
*/
|
|
93879
|
+
"application/json": {
|
|
93880
|
+
data: components["schemas"]["MetaAdsIntegration"] & Record<string, never>;
|
|
93881
|
+
};
|
|
93882
|
+
};
|
|
93883
|
+
};
|
|
93884
|
+
/** @description Validation error */
|
|
93885
|
+
400: {
|
|
93886
|
+
headers: {
|
|
93887
|
+
[name: string]: unknown;
|
|
93888
|
+
};
|
|
93889
|
+
content: {
|
|
93890
|
+
"application/json": components["schemas"]["Error"];
|
|
93891
|
+
};
|
|
93892
|
+
};
|
|
93893
|
+
/** @description Unauthorized */
|
|
93894
|
+
401: {
|
|
93895
|
+
headers: {
|
|
93896
|
+
[name: string]: unknown;
|
|
93897
|
+
};
|
|
93898
|
+
content: {
|
|
93899
|
+
"application/json": components["schemas"]["Error"];
|
|
93900
|
+
};
|
|
93901
|
+
};
|
|
93902
|
+
/** @description Forbidden */
|
|
93903
|
+
403: {
|
|
93904
|
+
headers: {
|
|
93905
|
+
[name: string]: unknown;
|
|
93906
|
+
};
|
|
93907
|
+
content: {
|
|
93908
|
+
"application/json": components["schemas"]["Error"];
|
|
93909
|
+
};
|
|
93910
|
+
};
|
|
93911
|
+
/** @description Not found */
|
|
93912
|
+
404: {
|
|
93913
|
+
headers: {
|
|
93914
|
+
[name: string]: unknown;
|
|
93915
|
+
};
|
|
93916
|
+
content: {
|
|
93917
|
+
"application/json": components["schemas"]["Error"];
|
|
93918
|
+
};
|
|
93919
|
+
};
|
|
93920
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93921
|
+
409: {
|
|
93922
|
+
headers: {
|
|
93923
|
+
[name: string]: unknown;
|
|
93924
|
+
};
|
|
93925
|
+
content: {
|
|
93926
|
+
"application/json": components["schemas"]["Error"];
|
|
93927
|
+
};
|
|
93928
|
+
};
|
|
93929
|
+
/** @description The picker’s parked provider token is gone — `{ error: { code: "reconnect" } }` */
|
|
93930
|
+
410: {
|
|
93931
|
+
headers: {
|
|
93932
|
+
[name: string]: unknown;
|
|
93933
|
+
};
|
|
93934
|
+
content: {
|
|
93935
|
+
"application/json": components["schemas"]["Error"];
|
|
93936
|
+
};
|
|
93937
|
+
};
|
|
93938
|
+
/** @description Rate limited */
|
|
93939
|
+
429: {
|
|
93940
|
+
headers: {
|
|
93941
|
+
[name: string]: unknown;
|
|
93942
|
+
};
|
|
93943
|
+
content: {
|
|
93944
|
+
"application/json": components["schemas"]["Error"];
|
|
93945
|
+
};
|
|
93946
|
+
};
|
|
93947
|
+
};
|
|
93948
|
+
};
|
|
92629
93949
|
delete?: never;
|
|
92630
93950
|
options?: never;
|
|
92631
93951
|
head?: never;
|
|
92632
93952
|
patch?: never;
|
|
92633
93953
|
trace?: never;
|
|
92634
93954
|
};
|
|
92635
|
-
"/
|
|
93955
|
+
"/integrations/meta-ads/ads": {
|
|
92636
93956
|
parameters: {
|
|
92637
93957
|
query?: never;
|
|
92638
93958
|
header?: never;
|
|
92639
93959
|
path?: never;
|
|
92640
93960
|
cookie?: never;
|
|
92641
93961
|
};
|
|
92642
|
-
get?: never;
|
|
92643
|
-
put?: never;
|
|
92644
93962
|
/**
|
|
92645
|
-
*
|
|
92646
|
-
* @description
|
|
93963
|
+
* The tenant's click-to-WhatsApp ads, with connect/greeting checks
|
|
93964
|
+
* @description Reads the partner click-to-WhatsApp ads list with the tenant’s WhatsApp **partner** token — a different credential than the connect rail above’s delegated key — and derives two facts per ad: `checks.destination_connected` (the ad’s WhatsApp number, compared as E.164, is one of the tenant’s connected WhatsApp messaging accounts) and `checks.greeting_configured` (a "Saludo automático" — text or tappable ice breakers — is actually set).
|
|
92647
93965
|
*
|
|
92648
|
-
*
|
|
93966
|
+
* Requires `integrations:read` or `ads:read` (owner, admin and the Marketing role — not "any member"), free for every tenant (no Add-on gate).
|
|
92649
93967
|
*
|
|
92650
|
-
*
|
|
93968
|
+
* `data.state` is `not_connected` in TWO cases, told apart by an optional `reason`:
|
|
93969
|
+
* * no `reason` — the tenant has never connected a Meta Ads account (the integration row is missing or not `connected`).
|
|
93970
|
+
* * `reason: "whatsapp_not_connected"` — Meta Ads may be connected, but the tenant holds no `whatsapp_cloud` account carrying an partner token, so there is no scope to list ads under.
|
|
92651
93971
|
*
|
|
92652
|
-
* `
|
|
93972
|
+
* `cursor` is the provider’s own opaque keyset cursor (its `pagination.cursor`, a Meta ad id ascending), passed straight through as `after`. `next_cursor` is `null` once the provider reports `has_next: false`. `last_synced_at` is the max over the returned PAGE only, not a tenant-wide sync timestamp.
|
|
93973
|
+
*
|
|
93974
|
+
* 502 `UPSTREAM_ERROR` on a provider 5xx, timeout, or a response shape this route does not recognise. 502 `partner_token_invalid` when the provider answers 401 on the WhatsApp partner token — that token is never auto-rotated; the dealer must reconnect WhatsApp.
|
|
92653
93975
|
*/
|
|
92654
|
-
|
|
93976
|
+
get: {
|
|
92655
93977
|
parameters: {
|
|
92656
|
-
query?:
|
|
92657
|
-
|
|
92658
|
-
|
|
92659
|
-
"Idempotency-Key"?: string;
|
|
93978
|
+
query?: {
|
|
93979
|
+
cursor?: string;
|
|
93980
|
+
limit?: number;
|
|
92660
93981
|
};
|
|
93982
|
+
header?: never;
|
|
92661
93983
|
path?: never;
|
|
92662
93984
|
cookie?: never;
|
|
92663
93985
|
};
|
|
92664
|
-
requestBody?:
|
|
92665
|
-
content: {
|
|
92666
|
-
/**
|
|
92667
|
-
* @example {
|
|
92668
|
-
* "report": "conversations",
|
|
92669
|
-
* "window": {
|
|
92670
|
-
* "preset": "7d"
|
|
92671
|
-
* },
|
|
92672
|
-
* "range": {
|
|
92673
|
-
* "preset": "7d"
|
|
92674
|
-
* }
|
|
92675
|
-
* }
|
|
92676
|
-
*/
|
|
92677
|
-
"application/json": {
|
|
92678
|
-
/** @enum {string} */
|
|
92679
|
-
report_type: "overview" | "conversations" | "agents" | "ai_agents" | "bots" | "tags" | "channels" | "teams" | "leads" | "csat" | "sla" | "clinic_ocupacion" | "clinic_inasistencias" | "clinic_produccion" | "clinic_packs";
|
|
92680
|
-
range: {
|
|
92681
|
-
from: string;
|
|
92682
|
-
to: string;
|
|
92683
|
-
preset?: string;
|
|
92684
|
-
};
|
|
92685
|
-
};
|
|
92686
|
-
};
|
|
92687
|
-
};
|
|
93986
|
+
requestBody?: never;
|
|
92688
93987
|
responses: {
|
|
92689
|
-
/** @description
|
|
93988
|
+
/** @description A `not_connected` state (with or without a `reason`), or the connected page of ads */
|
|
92690
93989
|
200: {
|
|
92691
93990
|
headers: {
|
|
92692
93991
|
[name: string]: unknown;
|
|
92693
93992
|
};
|
|
92694
93993
|
content: {
|
|
92695
|
-
|
|
93994
|
+
/**
|
|
93995
|
+
* @example {
|
|
93996
|
+
* "data": {
|
|
93997
|
+
* "state": "connected",
|
|
93998
|
+
* "items": [
|
|
93999
|
+
* {
|
|
94000
|
+
* "ad_id": "1234567890123",
|
|
94001
|
+
* "ad_name": "Test drive fin de semana",
|
|
94002
|
+
* "ad_status": "ACTIVE",
|
|
94003
|
+
* "campaign": {
|
|
94004
|
+
* "id": "6543210987654",
|
|
94005
|
+
* "name": "Leads · WhatsApp"
|
|
94006
|
+
* },
|
|
94007
|
+
* "ad_set": {
|
|
94008
|
+
* "id": "6543210987655",
|
|
94009
|
+
* "name": "Región Metropolitana"
|
|
94010
|
+
* },
|
|
94011
|
+
* "destination": {
|
|
94012
|
+
* "type": "whatsapp",
|
|
94013
|
+
* "whatsapp_phone_number": "+56912345678",
|
|
94014
|
+
* "page_id": "998877665544"
|
|
94015
|
+
* },
|
|
94016
|
+
* "cta_type": "WHATSAPP_MESSAGE",
|
|
94017
|
+
* "greeting": {
|
|
94018
|
+
* "text": "¡Hola! Cuéntanos qué auto buscas.",
|
|
94019
|
+
* "autofill_message": "Quiero agendar un test drive",
|
|
94020
|
+
* "ice_breakers": [
|
|
94021
|
+
* "Ver stock disponible",
|
|
94022
|
+
* "Agendar test drive"
|
|
94023
|
+
* ],
|
|
94024
|
+
* "landing_screen_type": "welcome_message"
|
|
94025
|
+
* },
|
|
94026
|
+
* "greeting_status": "present",
|
|
94027
|
+
* "checks": {
|
|
94028
|
+
* "destination_connected": true,
|
|
94029
|
+
* "greeting_configured": true
|
|
94030
|
+
* },
|
|
94031
|
+
* "last_synced_at": "2026-09-23T14:00:00.000Z"
|
|
94032
|
+
* }
|
|
94033
|
+
* ],
|
|
94034
|
+
* "next_cursor": null,
|
|
94035
|
+
* "last_synced_at": "2026-09-23T14:00:00.000Z"
|
|
94036
|
+
* }
|
|
94037
|
+
* }
|
|
94038
|
+
*/
|
|
94039
|
+
"application/json": {
|
|
94040
|
+
data: components["schemas"]["MetaAdsAdsResponse"];
|
|
94041
|
+
};
|
|
92696
94042
|
};
|
|
92697
94043
|
};
|
|
92698
94044
|
/** @description Validation error */
|
|
@@ -92751,13 +94097,15 @@ interface paths {
|
|
|
92751
94097
|
};
|
|
92752
94098
|
};
|
|
92753
94099
|
};
|
|
94100
|
+
put?: never;
|
|
94101
|
+
post?: never;
|
|
92754
94102
|
delete?: never;
|
|
92755
94103
|
options?: never;
|
|
92756
94104
|
head?: never;
|
|
92757
94105
|
patch?: never;
|
|
92758
94106
|
trace?: never;
|
|
92759
94107
|
};
|
|
92760
|
-
"/
|
|
94108
|
+
"/integrations/connections": {
|
|
92761
94109
|
parameters: {
|
|
92762
94110
|
query?: never;
|
|
92763
94111
|
header?: never;
|
|
@@ -92765,8 +94113,10 @@ interface paths {
|
|
|
92765
94113
|
cookie?: never;
|
|
92766
94114
|
};
|
|
92767
94115
|
/**
|
|
92768
|
-
* List
|
|
92769
|
-
* @description
|
|
94116
|
+
* List the workspace’s provider connections (CRM, payments)
|
|
94117
|
+
* @description One card per connectable provider — GoHighLevel, Mercado Pago — ALWAYS every provider, never-connected ones included (`state: "not_connected"`), so an integrations screen renders from this one read. Each card is exactly what `GET /integrations/connections/{provider}` returns.
|
|
94118
|
+
*
|
|
94119
|
+
* Requires `integrations:read` (owner and admin).
|
|
92770
94120
|
*/
|
|
92771
94121
|
get: {
|
|
92772
94122
|
parameters: {
|
|
@@ -92777,7 +94127,7 @@ interface paths {
|
|
|
92777
94127
|
};
|
|
92778
94128
|
requestBody?: never;
|
|
92779
94129
|
responses: {
|
|
92780
|
-
/** @description
|
|
94130
|
+
/** @description Every provider connection card */
|
|
92781
94131
|
200: {
|
|
92782
94132
|
headers: {
|
|
92783
94133
|
[name: string]: unknown;
|
|
@@ -92787,24 +94137,72 @@ interface paths {
|
|
|
92787
94137
|
* @example {
|
|
92788
94138
|
* "data": [
|
|
92789
94139
|
* {
|
|
92790
|
-
* "
|
|
92791
|
-
* "
|
|
92792
|
-
* "
|
|
92793
|
-
* "
|
|
92794
|
-
* "
|
|
92795
|
-
*
|
|
92796
|
-
*
|
|
92797
|
-
* "
|
|
92798
|
-
* "
|
|
94140
|
+
* "provider": "gohighlevel",
|
|
94141
|
+
* "display_name": "GoHighLevel",
|
|
94142
|
+
* "category": "crm",
|
|
94143
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
94144
|
+
* "last_account": null,
|
|
94145
|
+
* "last_attempt": null,
|
|
94146
|
+
* "disconnected_at": null,
|
|
94147
|
+
* "addon_active": true,
|
|
94148
|
+
* "state": "connecting",
|
|
94149
|
+
* "state_label": "Elige la subcuenta",
|
|
94150
|
+
* "account": null,
|
|
94151
|
+
* "reason": null,
|
|
94152
|
+
* "next_step": {
|
|
94153
|
+
* "action": "choose_account",
|
|
94154
|
+
* "label": "Elegir subcuenta"
|
|
94155
|
+
* },
|
|
94156
|
+
* "attempt": {
|
|
94157
|
+
* "step": "choose_account",
|
|
94158
|
+
* "handoff": {
|
|
94159
|
+
* "id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21",
|
|
94160
|
+
* "expires_at": "2026-09-27T15:45:00.000Z"
|
|
94161
|
+
* },
|
|
94162
|
+
* "candidates": [
|
|
94163
|
+
* {
|
|
94164
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
94165
|
+
* "name": "Agencia Ejemplo — Ventas"
|
|
94166
|
+
* },
|
|
94167
|
+
* {
|
|
94168
|
+
* "external_id": "loc_3MnB7wQ1yZ",
|
|
94169
|
+
* "name": "Agencia Ejemplo — Soporte"
|
|
94170
|
+
* }
|
|
94171
|
+
* ],
|
|
94172
|
+
* "selection_expires_at": "2026-09-27T16:00:00.000Z",
|
|
94173
|
+
* "prompt": "Elige la subcuenta de GoHighLevel que quieres conectar."
|
|
94174
|
+
* },
|
|
94175
|
+
* "connected_at": null,
|
|
94176
|
+
* "last_synced_at": null,
|
|
94177
|
+
* "updated_at": "2026-09-27T15:02:00.000Z"
|
|
94178
|
+
* },
|
|
94179
|
+
* {
|
|
94180
|
+
* "provider": "mercadopago",
|
|
94181
|
+
* "display_name": "Mercado Pago",
|
|
94182
|
+
* "category": "payments",
|
|
94183
|
+
* "description": "Registra los pagos que recibes para saber cuántas ventas trae cada campaña.",
|
|
94184
|
+
* "state": "not_connected",
|
|
94185
|
+
* "state_label": "Sin conectar",
|
|
94186
|
+
* "account": null,
|
|
94187
|
+
* "last_account": null,
|
|
94188
|
+
* "reason": null,
|
|
94189
|
+
* "last_attempt": null,
|
|
94190
|
+
* "next_step": {
|
|
94191
|
+
* "action": "connect",
|
|
94192
|
+
* "label": "Conectar"
|
|
94193
|
+
* },
|
|
94194
|
+
* "attempt": null,
|
|
94195
|
+
* "connected_at": null,
|
|
94196
|
+
* "disconnected_at": null,
|
|
94197
|
+
* "last_synced_at": null,
|
|
94198
|
+
* "updated_at": null,
|
|
94199
|
+
* "addon_active": true
|
|
92799
94200
|
* }
|
|
92800
94201
|
* ]
|
|
92801
94202
|
* }
|
|
92802
94203
|
*/
|
|
92803
94204
|
"application/json": {
|
|
92804
|
-
data
|
|
92805
|
-
meta?: {
|
|
92806
|
-
[key: string]: unknown;
|
|
92807
|
-
};
|
|
94205
|
+
data: components["schemas"]["ProviderConnection"][];
|
|
92808
94206
|
};
|
|
92809
94207
|
};
|
|
92810
94208
|
};
|
|
@@ -92872,7 +94270,7 @@ interface paths {
|
|
|
92872
94270
|
patch?: never;
|
|
92873
94271
|
trace?: never;
|
|
92874
94272
|
};
|
|
92875
|
-
"/integrations/
|
|
94273
|
+
"/integrations/connections/{provider}": {
|
|
92876
94274
|
parameters: {
|
|
92877
94275
|
query?: never;
|
|
92878
94276
|
header?: never;
|
|
@@ -92880,23 +94278,27 @@ interface paths {
|
|
|
92880
94278
|
cookie?: never;
|
|
92881
94279
|
};
|
|
92882
94280
|
/**
|
|
92883
|
-
* Read
|
|
92884
|
-
* @description
|
|
94281
|
+
* Read one provider connection card
|
|
94282
|
+
* @description Everything the card renders, in one read: the state and its label, the connected account, the reason with a ready-to-render sentence, how the latest re-authorization ended (`last_attempt`), the next step with its button label, when it connected / stopped / last synced, and — only while a connect is in flight — the attempt. Never null: a workspace that never connected gets `state: "not_connected"`.
|
|
92885
94283
|
*
|
|
92886
|
-
*
|
|
94284
|
+
* A connection whose last sync failed stays `connected` with `reason.code: "sync_error"` (label «Problema de sincronización») and a `reconnect` next step; only a grant the provider no longer honours is `needs_reconnect`.
|
|
92887
94285
|
*
|
|
92888
|
-
*
|
|
94286
|
+
* While an account picker is open the candidates are re-read from the provider when older than five minutes; every other state is a database read only.
|
|
94287
|
+
*
|
|
94288
|
+
* Requires `integrations:read` (owner and admin).
|
|
92889
94289
|
*/
|
|
92890
94290
|
get: {
|
|
92891
94291
|
parameters: {
|
|
92892
94292
|
query?: never;
|
|
92893
94293
|
header?: never;
|
|
92894
|
-
path
|
|
94294
|
+
path: {
|
|
94295
|
+
provider: "gohighlevel" | "mercadopago";
|
|
94296
|
+
};
|
|
92895
94297
|
cookie?: never;
|
|
92896
94298
|
};
|
|
92897
94299
|
requestBody?: never;
|
|
92898
94300
|
responses: {
|
|
92899
|
-
/** @description The
|
|
94301
|
+
/** @description The provider connection card */
|
|
92900
94302
|
200: {
|
|
92901
94303
|
headers: {
|
|
92902
94304
|
[name: string]: unknown;
|
|
@@ -92904,11 +94306,35 @@ interface paths {
|
|
|
92904
94306
|
content: {
|
|
92905
94307
|
/**
|
|
92906
94308
|
* @example {
|
|
92907
|
-
* "data":
|
|
94309
|
+
* "data": {
|
|
94310
|
+
* "provider": "gohighlevel",
|
|
94311
|
+
* "display_name": "GoHighLevel",
|
|
94312
|
+
* "category": "crm",
|
|
94313
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
94314
|
+
* "last_account": null,
|
|
94315
|
+
* "last_attempt": null,
|
|
94316
|
+
* "disconnected_at": null,
|
|
94317
|
+
* "addon_active": true,
|
|
94318
|
+
* "state": "connected",
|
|
94319
|
+
* "state_label": "Conectado",
|
|
94320
|
+
* "account": {
|
|
94321
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
94322
|
+
* "name": "Agencia Ejemplo"
|
|
94323
|
+
* },
|
|
94324
|
+
* "reason": null,
|
|
94325
|
+
* "next_step": {
|
|
94326
|
+
* "action": "none",
|
|
94327
|
+
* "label": null
|
|
94328
|
+
* },
|
|
94329
|
+
* "attempt": null,
|
|
94330
|
+
* "connected_at": "2026-09-27T15:04:00.000Z",
|
|
94331
|
+
* "last_synced_at": "2026-09-27T15:20:00.000Z",
|
|
94332
|
+
* "updated_at": "2026-09-27T15:20:00.000Z"
|
|
94333
|
+
* }
|
|
92908
94334
|
* }
|
|
92909
94335
|
*/
|
|
92910
94336
|
"application/json": {
|
|
92911
|
-
data: components["schemas"]["
|
|
94337
|
+
data: components["schemas"]["ProviderConnection"];
|
|
92912
94338
|
};
|
|
92913
94339
|
};
|
|
92914
94340
|
};
|
|
@@ -92930,6 +94356,31 @@ interface paths {
|
|
|
92930
94356
|
"application/json": components["schemas"]["Error"];
|
|
92931
94357
|
};
|
|
92932
94358
|
};
|
|
94359
|
+
/** @description The Vitrina Ads add-on is not active and nothing is connected (or in flight) for this provider. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. A connection that outlived the add-on is never refused here: it stays readable, finishable and disconnectable. */
|
|
94360
|
+
402: {
|
|
94361
|
+
headers: {
|
|
94362
|
+
[name: string]: unknown;
|
|
94363
|
+
};
|
|
94364
|
+
content: {
|
|
94365
|
+
/**
|
|
94366
|
+
* @example {
|
|
94367
|
+
* "error": {
|
|
94368
|
+
* "code": "ENTITLEMENT_NOT_ACTIVE",
|
|
94369
|
+
* "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
|
|
94370
|
+
* "details": {
|
|
94371
|
+
* "required": [
|
|
94372
|
+
* "vitrina_ads"
|
|
94373
|
+
* ],
|
|
94374
|
+
* "active": [],
|
|
94375
|
+
* "feature": "vitrina_ads",
|
|
94376
|
+
* "entitlement_state": "off"
|
|
94377
|
+
* }
|
|
94378
|
+
* }
|
|
94379
|
+
* }
|
|
94380
|
+
*/
|
|
94381
|
+
"application/json": components["schemas"]["Error"];
|
|
94382
|
+
};
|
|
94383
|
+
};
|
|
92933
94384
|
/** @description Forbidden */
|
|
92934
94385
|
403: {
|
|
92935
94386
|
headers: {
|
|
@@ -92976,7 +94427,7 @@ interface paths {
|
|
|
92976
94427
|
patch?: never;
|
|
92977
94428
|
trace?: never;
|
|
92978
94429
|
};
|
|
92979
|
-
"/integrations/
|
|
94430
|
+
"/integrations/connections/{provider}/connect": {
|
|
92980
94431
|
parameters: {
|
|
92981
94432
|
query?: never;
|
|
92982
94433
|
header?: never;
|
|
@@ -92986,14 +94437,14 @@ interface paths {
|
|
|
92986
94437
|
get?: never;
|
|
92987
94438
|
put?: never;
|
|
92988
94439
|
/**
|
|
92989
|
-
* Start a
|
|
92990
|
-
* @description
|
|
94440
|
+
* Start (or resume) a provider connect
|
|
94441
|
+
* @description Starts the provider’s consent and answers the URL to send the WHOLE page to — straight to the provider’s own consent screen, which names this app. Every ending (connected, several accounts to choose from, cancelled, refused, expired) comes back to `return_to` with `connection_return=<provider>`, `connection_state`, and the provider’s `status`, `reason` and `handoff_id`; pass all of them to `POST …/return`, then strip them from the address bar.
|
|
92991
94442
|
*
|
|
92992
|
-
* `return_to` must be an absolute URL on the app’s own origin
|
|
94443
|
+
* `return_to` must be an absolute URL on the app’s own origin (400 otherwise).
|
|
92993
94444
|
*
|
|
92994
|
-
* **A second click
|
|
94445
|
+
* **Idempotent.** A second click while a consent is live for the same `return_to` answers the SAME `url` and `handoff_id`. It works from every state: a first connect, a retry, a reconnect (`needs_reconnect`), a re-authorization of a connected account. Only a first connect moves the card to `connecting`; a reconnect keeps its state until the new consent lands.
|
|
92995
94446
|
*
|
|
92996
|
-
*
|
|
94447
|
+
* Requires `integrations:write` (owner and admin).
|
|
92997
94448
|
*/
|
|
92998
94449
|
post: {
|
|
92999
94450
|
parameters: {
|
|
@@ -93002,21 +94453,23 @@ interface paths {
|
|
|
93002
94453
|
/** @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. */
|
|
93003
94454
|
"Idempotency-Key"?: string;
|
|
93004
94455
|
};
|
|
93005
|
-
path
|
|
94456
|
+
path: {
|
|
94457
|
+
provider: "gohighlevel" | "mercadopago";
|
|
94458
|
+
};
|
|
93006
94459
|
cookie?: never;
|
|
93007
94460
|
};
|
|
93008
94461
|
requestBody?: {
|
|
93009
94462
|
content: {
|
|
93010
94463
|
/**
|
|
93011
94464
|
* @example {
|
|
93012
|
-
* "return_to": "https://app.vitrinadev.com/settings/integraciones
|
|
94465
|
+
* "return_to": "https://app.vitrinadev.com/w/agencia/settings/integraciones"
|
|
93013
94466
|
* }
|
|
93014
94467
|
*/
|
|
93015
|
-
"application/json": components["schemas"]["
|
|
94468
|
+
"application/json": components["schemas"]["ProviderConnectBody"];
|
|
93016
94469
|
};
|
|
93017
94470
|
};
|
|
93018
94471
|
responses: {
|
|
93019
|
-
/** @description The consent URL, its hand-off id, and
|
|
94472
|
+
/** @description The consent URL, its hand-off id and expiry, and the card */
|
|
93020
94473
|
200: {
|
|
93021
94474
|
headers: {
|
|
93022
94475
|
[name: string]: unknown;
|
|
@@ -93025,14 +94478,45 @@ interface paths {
|
|
|
93025
94478
|
/**
|
|
93026
94479
|
* @example {
|
|
93027
94480
|
* "data": {
|
|
93028
|
-
* "url": "https://
|
|
93029
|
-
* "handoff_id": "
|
|
93030
|
-
* "expires_at": "2026-09-
|
|
94481
|
+
* "url": "https://connect.example.com/gohighlevel/start?h=4d8f2a91c6b3",
|
|
94482
|
+
* "handoff_id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21",
|
|
94483
|
+
* "expires_at": "2026-09-27T15:45:00.000Z",
|
|
94484
|
+
* "connection": {
|
|
94485
|
+
* "provider": "gohighlevel",
|
|
94486
|
+
* "display_name": "GoHighLevel",
|
|
94487
|
+
* "category": "crm",
|
|
94488
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
94489
|
+
* "last_account": null,
|
|
94490
|
+
* "last_attempt": null,
|
|
94491
|
+
* "disconnected_at": null,
|
|
94492
|
+
* "addon_active": true,
|
|
94493
|
+
* "state": "connecting",
|
|
94494
|
+
* "state_label": "Conectando",
|
|
94495
|
+
* "account": null,
|
|
94496
|
+
* "reason": null,
|
|
94497
|
+
* "next_step": {
|
|
94498
|
+
* "action": "resume",
|
|
94499
|
+
* "label": "Continuar en GoHighLevel"
|
|
94500
|
+
* },
|
|
94501
|
+
* "attempt": {
|
|
94502
|
+
* "step": "consent",
|
|
94503
|
+
* "handoff": {
|
|
94504
|
+
* "id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21",
|
|
94505
|
+
* "expires_at": "2026-09-27T15:45:00.000Z"
|
|
94506
|
+
* },
|
|
94507
|
+
* "candidates": null,
|
|
94508
|
+
* "selection_expires_at": null,
|
|
94509
|
+
* "prompt": "Termina la autorización en GoHighLevel para conectar."
|
|
94510
|
+
* },
|
|
94511
|
+
* "connected_at": null,
|
|
94512
|
+
* "last_synced_at": null,
|
|
94513
|
+
* "updated_at": "2026-09-27T15:00:00.000Z"
|
|
94514
|
+
* }
|
|
93031
94515
|
* }
|
|
93032
94516
|
* }
|
|
93033
94517
|
*/
|
|
93034
94518
|
"application/json": {
|
|
93035
|
-
data: components["schemas"]["
|
|
94519
|
+
data: components["schemas"]["ProviderConnectResult"];
|
|
93036
94520
|
};
|
|
93037
94521
|
};
|
|
93038
94522
|
};
|
|
@@ -93054,6 +94538,31 @@ interface paths {
|
|
|
93054
94538
|
"application/json": components["schemas"]["Error"];
|
|
93055
94539
|
};
|
|
93056
94540
|
};
|
|
94541
|
+
/** @description The Vitrina Ads add-on is not active and nothing is connected (or in flight) for this provider. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. A connection that outlived the add-on is never refused here: it stays readable, finishable and disconnectable. */
|
|
94542
|
+
402: {
|
|
94543
|
+
headers: {
|
|
94544
|
+
[name: string]: unknown;
|
|
94545
|
+
};
|
|
94546
|
+
content: {
|
|
94547
|
+
/**
|
|
94548
|
+
* @example {
|
|
94549
|
+
* "error": {
|
|
94550
|
+
* "code": "ENTITLEMENT_NOT_ACTIVE",
|
|
94551
|
+
* "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
|
|
94552
|
+
* "details": {
|
|
94553
|
+
* "required": [
|
|
94554
|
+
* "vitrina_ads"
|
|
94555
|
+
* ],
|
|
94556
|
+
* "active": [],
|
|
94557
|
+
* "feature": "vitrina_ads",
|
|
94558
|
+
* "entitlement_state": "off"
|
|
94559
|
+
* }
|
|
94560
|
+
* }
|
|
94561
|
+
* }
|
|
94562
|
+
*/
|
|
94563
|
+
"application/json": components["schemas"]["Error"];
|
|
94564
|
+
};
|
|
94565
|
+
};
|
|
93057
94566
|
/** @description Forbidden */
|
|
93058
94567
|
403: {
|
|
93059
94568
|
headers: {
|
|
@@ -93098,7 +94607,7 @@ interface paths {
|
|
|
93098
94607
|
patch?: never;
|
|
93099
94608
|
trace?: never;
|
|
93100
94609
|
};
|
|
93101
|
-
"/integrations/
|
|
94610
|
+
"/integrations/connections/{provider}/return": {
|
|
93102
94611
|
parameters: {
|
|
93103
94612
|
query?: never;
|
|
93104
94613
|
header?: never;
|
|
@@ -93108,19 +94617,19 @@ interface paths {
|
|
|
93108
94617
|
get?: never;
|
|
93109
94618
|
put?: never;
|
|
93110
94619
|
/**
|
|
93111
|
-
* Settle a
|
|
93112
|
-
* @description
|
|
94620
|
+
* Settle a provider connect after the admin comes back
|
|
94621
|
+
* @description Settles the connect on the provider’s own record of the consent — the `status` and `reason` from the return URL are hints only (a URL can be typed):
|
|
93113
94622
|
*
|
|
93114
|
-
* * `
|
|
93115
|
-
* *
|
|
93116
|
-
* *
|
|
93117
|
-
* *
|
|
94623
|
+
* * connected → `state: "connected"` with the account read back from the provider;
|
|
94624
|
+
* * several accounts (GoHighLevel) → `attempt.step: "choose_account"` with `attempt.candidates`;
|
|
94625
|
+
* * cancelled / refused / expired → the attempt ends with a SPECIFIC `reason` (`user_cancelled`, `account_connected_elsewhere`, `no_candidates`, `provider_denied`, …), never folded into one generic failure. On a card that was already connected the state is unchanged and the outcome is `last_attempt`;
|
|
94626
|
+
* * not finished yet → the card comes back unchanged. If the return URL says the attempt failed with the retryable `internal_error`, the reason is recorded and the SAME consent link stays live for a retry; any other failure ends the attempt.
|
|
93118
94627
|
*
|
|
93119
|
-
*
|
|
94628
|
+
* Every field is optional: a stripped query string still settles the workspace’s own pending consent (there is at most one). **Idempotent:** re-posting for a consent already settled answers the card as it stands. A consent finished in an OLDER tab after a newer connect answers the connected card.
|
|
93120
94629
|
*
|
|
93121
|
-
*
|
|
94630
|
+
* 409 `handoff_mismatch` when the `handoff_id`/`state` presented is neither this card’s consent nor its last one and nothing is connected. 502 when the provider could not be reached — nothing is settled; retry.
|
|
93122
94631
|
*
|
|
93123
|
-
*
|
|
94632
|
+
* Requires `integrations:write`.
|
|
93124
94633
|
*/
|
|
93125
94634
|
post: {
|
|
93126
94635
|
parameters: {
|
|
@@ -93129,21 +94638,25 @@ interface paths {
|
|
|
93129
94638
|
/** @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. */
|
|
93130
94639
|
"Idempotency-Key"?: string;
|
|
93131
94640
|
};
|
|
93132
|
-
path
|
|
94641
|
+
path: {
|
|
94642
|
+
provider: "gohighlevel" | "mercadopago";
|
|
94643
|
+
};
|
|
93133
94644
|
cookie?: never;
|
|
93134
94645
|
};
|
|
93135
94646
|
requestBody?: {
|
|
93136
94647
|
content: {
|
|
93137
94648
|
/**
|
|
93138
94649
|
* @example {
|
|
93139
|
-
* "
|
|
94650
|
+
* "handoff_id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21",
|
|
94651
|
+
* "state": "9f3a2d7c8b1e4a2f",
|
|
94652
|
+
* "status": "success"
|
|
93140
94653
|
* }
|
|
93141
94654
|
*/
|
|
93142
|
-
"application/json": components["schemas"]["
|
|
94655
|
+
"application/json": components["schemas"]["ProviderReturnBody"];
|
|
93143
94656
|
};
|
|
93144
94657
|
};
|
|
93145
94658
|
responses: {
|
|
93146
|
-
/** @description The settled
|
|
94659
|
+
/** @description The settled card */
|
|
93147
94660
|
200: {
|
|
93148
94661
|
headers: {
|
|
93149
94662
|
[name: string]: unknown;
|
|
@@ -93152,30 +94665,34 @@ interface paths {
|
|
|
93152
94665
|
/**
|
|
93153
94666
|
* @example {
|
|
93154
94667
|
* "data": {
|
|
93155
|
-
* "
|
|
93156
|
-
* "
|
|
93157
|
-
* "
|
|
93158
|
-
* "
|
|
93159
|
-
* "
|
|
94668
|
+
* "provider": "gohighlevel",
|
|
94669
|
+
* "display_name": "GoHighLevel",
|
|
94670
|
+
* "category": "crm",
|
|
94671
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
94672
|
+
* "last_account": null,
|
|
94673
|
+
* "last_attempt": null,
|
|
93160
94674
|
* "disconnected_at": null,
|
|
94675
|
+
* "addon_active": true,
|
|
94676
|
+
* "state": "connected",
|
|
94677
|
+
* "state_label": "Conectado",
|
|
93161
94678
|
* "account": {
|
|
93162
|
-
* "
|
|
93163
|
-
* "name": "
|
|
93164
|
-
* "currency": "CLP",
|
|
93165
|
-
* "timezone": "America/Santiago",
|
|
93166
|
-
* "delivers_spend": true,
|
|
93167
|
-
* "provider_connection_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
93168
|
-
* "atribu_connection_id": "c0c0c0c0-0000-4000-8000-000000000001"
|
|
94679
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
94680
|
+
* "name": "Agencia Ejemplo"
|
|
93169
94681
|
* },
|
|
93170
|
-
* "
|
|
93171
|
-
* "
|
|
93172
|
-
*
|
|
93173
|
-
*
|
|
94682
|
+
* "reason": null,
|
|
94683
|
+
* "next_step": {
|
|
94684
|
+
* "action": "none",
|
|
94685
|
+
* "label": null
|
|
94686
|
+
* },
|
|
94687
|
+
* "attempt": null,
|
|
94688
|
+
* "connected_at": "2026-09-27T15:04:00.000Z",
|
|
94689
|
+
* "last_synced_at": "2026-09-27T15:20:00.000Z",
|
|
94690
|
+
* "updated_at": "2026-09-27T15:20:00.000Z"
|
|
93174
94691
|
* }
|
|
93175
94692
|
* }
|
|
93176
94693
|
*/
|
|
93177
94694
|
"application/json": {
|
|
93178
|
-
data: components["schemas"]["
|
|
94695
|
+
data: components["schemas"]["ProviderConnection"];
|
|
93179
94696
|
};
|
|
93180
94697
|
};
|
|
93181
94698
|
};
|
|
@@ -93197,6 +94714,31 @@ interface paths {
|
|
|
93197
94714
|
"application/json": components["schemas"]["Error"];
|
|
93198
94715
|
};
|
|
93199
94716
|
};
|
|
94717
|
+
/** @description The Vitrina Ads add-on is not active and nothing is connected (or in flight) for this provider. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. A connection that outlived the add-on is never refused here: it stays readable, finishable and disconnectable. */
|
|
94718
|
+
402: {
|
|
94719
|
+
headers: {
|
|
94720
|
+
[name: string]: unknown;
|
|
94721
|
+
};
|
|
94722
|
+
content: {
|
|
94723
|
+
/**
|
|
94724
|
+
* @example {
|
|
94725
|
+
* "error": {
|
|
94726
|
+
* "code": "ENTITLEMENT_NOT_ACTIVE",
|
|
94727
|
+
* "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
|
|
94728
|
+
* "details": {
|
|
94729
|
+
* "required": [
|
|
94730
|
+
* "vitrina_ads"
|
|
94731
|
+
* ],
|
|
94732
|
+
* "active": [],
|
|
94733
|
+
* "feature": "vitrina_ads",
|
|
94734
|
+
* "entitlement_state": "off"
|
|
94735
|
+
* }
|
|
94736
|
+
* }
|
|
94737
|
+
* }
|
|
94738
|
+
*/
|
|
94739
|
+
"application/json": components["schemas"]["Error"];
|
|
94740
|
+
};
|
|
94741
|
+
};
|
|
93200
94742
|
/** @description Forbidden */
|
|
93201
94743
|
403: {
|
|
93202
94744
|
headers: {
|
|
@@ -93215,131 +94757,20 @@ interface paths {
|
|
|
93215
94757
|
"application/json": components["schemas"]["Error"];
|
|
93216
94758
|
};
|
|
93217
94759
|
};
|
|
93218
|
-
/** @description
|
|
94760
|
+
/** @description `handoff_mismatch` — a stale tab finishing another consent. */
|
|
93219
94761
|
409: {
|
|
93220
|
-
headers: {
|
|
93221
|
-
[name: string]: unknown;
|
|
93222
|
-
};
|
|
93223
|
-
content: {
|
|
93224
|
-
"application/json": components["schemas"]["Error"];
|
|
93225
|
-
};
|
|
93226
|
-
};
|
|
93227
|
-
/** @description Rate limited */
|
|
93228
|
-
429: {
|
|
93229
|
-
headers: {
|
|
93230
|
-
[name: string]: unknown;
|
|
93231
|
-
};
|
|
93232
|
-
content: {
|
|
93233
|
-
"application/json": components["schemas"]["Error"];
|
|
93234
|
-
};
|
|
93235
|
-
};
|
|
93236
|
-
};
|
|
93237
|
-
};
|
|
93238
|
-
delete?: never;
|
|
93239
|
-
options?: never;
|
|
93240
|
-
head?: never;
|
|
93241
|
-
patch?: never;
|
|
93242
|
-
trace?: never;
|
|
93243
|
-
};
|
|
93244
|
-
"/integrations/meta-ads/disconnect": {
|
|
93245
|
-
parameters: {
|
|
93246
|
-
query?: never;
|
|
93247
|
-
header?: never;
|
|
93248
|
-
path?: never;
|
|
93249
|
-
cookie?: never;
|
|
93250
|
-
};
|
|
93251
|
-
get?: never;
|
|
93252
|
-
put?: never;
|
|
93253
|
-
/**
|
|
93254
|
-
* Disconnect the workspace’s Meta Ads ad account
|
|
93255
|
-
* @description Calls the provider’s disconnect for the connection on the delegated key and settles the row `disconnected`, keeping its history: `account_label` and `connected_at` stay, and `config.last_account` remembers which account this was so the card can still name it. Reconnecting afterwards is a plain new `/connect` — it mints a fresh hand-off. A tenant must always be able to walk away from a connection it made.
|
|
93256
|
-
*
|
|
93257
|
-
* A row with nothing at the provider to revoke — `pending` / `pending_selection` with no connection — is cancelled LOCALLY: no provider call, the row moves straight to `disconnected`, and the pending hand-off simply expires on its own (the provider has no endpoint to cancel one early). A row already `disconnected` answers 200 unchanged (idempotent).
|
|
93258
|
-
*
|
|
93259
|
-
* 409 `sync_in_flight` when the provider is mid-sync on the connection — the row is left exactly as it was; the whole recovery is trying again in a few minutes. 502 `atribu_refused` when the provider’s own 403 says the delegated key is no longer good for this connection — also left unchanged. A 404 from the provider (the connection is already gone there) is treated as success: the state this call exists to ensure already holds.
|
|
93260
|
-
*/
|
|
93261
|
-
post: {
|
|
93262
|
-
parameters: {
|
|
93263
|
-
query?: never;
|
|
93264
|
-
header?: {
|
|
93265
|
-
/** @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. */
|
|
93266
|
-
"Idempotency-Key"?: string;
|
|
93267
|
-
};
|
|
93268
|
-
path?: never;
|
|
93269
|
-
cookie?: never;
|
|
93270
|
-
};
|
|
93271
|
-
requestBody?: never;
|
|
93272
|
-
responses: {
|
|
93273
|
-
/** @description The disconnected integration */
|
|
93274
|
-
200: {
|
|
93275
94762
|
headers: {
|
|
93276
94763
|
[name: string]: unknown;
|
|
93277
94764
|
};
|
|
93278
94765
|
content: {
|
|
93279
94766
|
/**
|
|
93280
94767
|
* @example {
|
|
93281
|
-
* "
|
|
93282
|
-
* "
|
|
93283
|
-
* "
|
|
93284
|
-
* "status": "disconnected",
|
|
93285
|
-
* "account_label": "Cuenta Meta Ads",
|
|
93286
|
-
* "connected_at": "2026-09-20T12:00:00.000Z",
|
|
93287
|
-
* "disconnected_at": "2026-09-23T15:10:00.000Z",
|
|
93288
|
-
* "account": null,
|
|
93289
|
-
* "error": null,
|
|
93290
|
-
* "handoff": null,
|
|
93291
|
-
* "candidates": null,
|
|
93292
|
-
* "updated_at": "2026-09-23T15:10:00.000Z"
|
|
94768
|
+
* "error": {
|
|
94769
|
+
* "code": "handoff_mismatch",
|
|
94770
|
+
* "message": "Esta conexión ya no está esperando ese enlace. Actualiza la página y vuelve a conectar."
|
|
93293
94771
|
* }
|
|
93294
94772
|
* }
|
|
93295
94773
|
*/
|
|
93296
|
-
"application/json": {
|
|
93297
|
-
data: components["schemas"]["MetaAdsIntegration"] & Record<string, never>;
|
|
93298
|
-
};
|
|
93299
|
-
};
|
|
93300
|
-
};
|
|
93301
|
-
/** @description Validation error */
|
|
93302
|
-
400: {
|
|
93303
|
-
headers: {
|
|
93304
|
-
[name: string]: unknown;
|
|
93305
|
-
};
|
|
93306
|
-
content: {
|
|
93307
|
-
"application/json": components["schemas"]["Error"];
|
|
93308
|
-
};
|
|
93309
|
-
};
|
|
93310
|
-
/** @description Unauthorized */
|
|
93311
|
-
401: {
|
|
93312
|
-
headers: {
|
|
93313
|
-
[name: string]: unknown;
|
|
93314
|
-
};
|
|
93315
|
-
content: {
|
|
93316
|
-
"application/json": components["schemas"]["Error"];
|
|
93317
|
-
};
|
|
93318
|
-
};
|
|
93319
|
-
/** @description Forbidden */
|
|
93320
|
-
403: {
|
|
93321
|
-
headers: {
|
|
93322
|
-
[name: string]: unknown;
|
|
93323
|
-
};
|
|
93324
|
-
content: {
|
|
93325
|
-
"application/json": components["schemas"]["Error"];
|
|
93326
|
-
};
|
|
93327
|
-
};
|
|
93328
|
-
/** @description Not found */
|
|
93329
|
-
404: {
|
|
93330
|
-
headers: {
|
|
93331
|
-
[name: string]: unknown;
|
|
93332
|
-
};
|
|
93333
|
-
content: {
|
|
93334
|
-
"application/json": components["schemas"]["Error"];
|
|
93335
|
-
};
|
|
93336
|
-
};
|
|
93337
|
-
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
93338
|
-
409: {
|
|
93339
|
-
headers: {
|
|
93340
|
-
[name: string]: unknown;
|
|
93341
|
-
};
|
|
93342
|
-
content: {
|
|
93343
94774
|
"application/json": components["schemas"]["Error"];
|
|
93344
94775
|
};
|
|
93345
94776
|
};
|
|
@@ -93360,7 +94791,7 @@ interface paths {
|
|
|
93360
94791
|
patch?: never;
|
|
93361
94792
|
trace?: never;
|
|
93362
94793
|
};
|
|
93363
|
-
"/integrations/
|
|
94794
|
+
"/integrations/connections/{provider}/finalize": {
|
|
93364
94795
|
parameters: {
|
|
93365
94796
|
query?: never;
|
|
93366
94797
|
header?: never;
|
|
@@ -93370,16 +94801,17 @@ interface paths {
|
|
|
93370
94801
|
get?: never;
|
|
93371
94802
|
put?: never;
|
|
93372
94803
|
/**
|
|
93373
|
-
*
|
|
93374
|
-
* @description
|
|
94804
|
+
* Choose the account to connect from an open picker
|
|
94805
|
+
* @description Completes an open account picker (`attempt.step: "choose_account"`) with one `attempt.candidates[].external_id`. Served only for providers whose consent can end in a choice (GoHighLevel sub-accounts); any other provider is 404. **Idempotent:** the same account again on a card it already connected answers the card.
|
|
93375
94806
|
*
|
|
93376
|
-
*
|
|
93377
|
-
*
|
|
93378
|
-
*
|
|
93379
|
-
*
|
|
93380
|
-
*
|
|
94807
|
+
* * 409 `handoff_mismatch` — `handoff_id` was sent and is not the consent this card is waiting on (a stale tab); refresh the card;
|
|
94808
|
+
* * 409 `not_selecting` — no choice is owed (refresh the card);
|
|
94809
|
+
* * 409 `account_connected_elsewhere` — that account lives on another Vitrina workspace; the picker STAYS open, choose another;
|
|
94810
|
+
* * 409 `selection_conflict` — another account was already chosen on this consent; connect again to change it;
|
|
94811
|
+
* * 410 `selection_expired` — the picker’s 60-minute window ended; connect again;
|
|
94812
|
+
* * 422 `candidate_unavailable` — the account is no longer reachable; the next card read refreshes the list.
|
|
93381
94813
|
*
|
|
93382
|
-
*
|
|
94814
|
+
* Requires `integrations:write`.
|
|
93383
94815
|
*/
|
|
93384
94816
|
post: {
|
|
93385
94817
|
parameters: {
|
|
@@ -93388,21 +94820,24 @@ interface paths {
|
|
|
93388
94820
|
/** @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. */
|
|
93389
94821
|
"Idempotency-Key"?: string;
|
|
93390
94822
|
};
|
|
93391
|
-
path
|
|
94823
|
+
path: {
|
|
94824
|
+
provider: "gohighlevel";
|
|
94825
|
+
};
|
|
93392
94826
|
cookie?: never;
|
|
93393
94827
|
};
|
|
93394
94828
|
requestBody?: {
|
|
93395
94829
|
content: {
|
|
93396
94830
|
/**
|
|
93397
94831
|
* @example {
|
|
93398
|
-
* "
|
|
94832
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
94833
|
+
* "handoff_id": "0f2f6b0a-9a2c-4f4e-9a1e-6f7f2a5c3b21"
|
|
93399
94834
|
* }
|
|
93400
94835
|
*/
|
|
93401
|
-
"application/json": components["schemas"]["
|
|
94836
|
+
"application/json": components["schemas"]["ProviderFinalizeBody"];
|
|
93402
94837
|
};
|
|
93403
94838
|
};
|
|
93404
94839
|
responses: {
|
|
93405
|
-
/** @description The
|
|
94840
|
+
/** @description The connected card */
|
|
93406
94841
|
200: {
|
|
93407
94842
|
headers: {
|
|
93408
94843
|
[name: string]: unknown;
|
|
@@ -93411,30 +94846,34 @@ interface paths {
|
|
|
93411
94846
|
/**
|
|
93412
94847
|
* @example {
|
|
93413
94848
|
* "data": {
|
|
93414
|
-
* "
|
|
93415
|
-
* "
|
|
93416
|
-
* "
|
|
93417
|
-
* "
|
|
93418
|
-
* "
|
|
94849
|
+
* "provider": "gohighlevel",
|
|
94850
|
+
* "display_name": "GoHighLevel",
|
|
94851
|
+
* "category": "crm",
|
|
94852
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
94853
|
+
* "last_account": null,
|
|
94854
|
+
* "last_attempt": null,
|
|
93419
94855
|
* "disconnected_at": null,
|
|
94856
|
+
* "addon_active": true,
|
|
94857
|
+
* "state": "connected",
|
|
94858
|
+
* "state_label": "Conectado",
|
|
93420
94859
|
* "account": {
|
|
93421
|
-
* "
|
|
93422
|
-
* "name": "
|
|
93423
|
-
* "currency": "CLP",
|
|
93424
|
-
* "timezone": "America/Santiago",
|
|
93425
|
-
* "delivers_spend": true,
|
|
93426
|
-
* "provider_connection_id": "c0c0c0c0-0000-4000-8000-000000000001",
|
|
93427
|
-
* "atribu_connection_id": "c0c0c0c0-0000-4000-8000-000000000001"
|
|
94860
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
94861
|
+
* "name": "Agencia Ejemplo"
|
|
93428
94862
|
* },
|
|
93429
|
-
* "
|
|
93430
|
-
* "
|
|
93431
|
-
*
|
|
93432
|
-
*
|
|
94863
|
+
* "reason": null,
|
|
94864
|
+
* "next_step": {
|
|
94865
|
+
* "action": "none",
|
|
94866
|
+
* "label": null
|
|
94867
|
+
* },
|
|
94868
|
+
* "attempt": null,
|
|
94869
|
+
* "connected_at": "2026-09-27T15:04:00.000Z",
|
|
94870
|
+
* "last_synced_at": "2026-09-27T15:20:00.000Z",
|
|
94871
|
+
* "updated_at": "2026-09-27T15:20:00.000Z"
|
|
93433
94872
|
* }
|
|
93434
94873
|
* }
|
|
93435
94874
|
*/
|
|
93436
94875
|
"application/json": {
|
|
93437
|
-
data: components["schemas"]["
|
|
94876
|
+
data: components["schemas"]["ProviderConnection"];
|
|
93438
94877
|
};
|
|
93439
94878
|
};
|
|
93440
94879
|
};
|
|
@@ -93456,6 +94895,31 @@ interface paths {
|
|
|
93456
94895
|
"application/json": components["schemas"]["Error"];
|
|
93457
94896
|
};
|
|
93458
94897
|
};
|
|
94898
|
+
/** @description The Vitrina Ads add-on is not active and nothing is connected (or in flight) for this provider. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. A connection that outlived the add-on is never refused here: it stays readable, finishable and disconnectable. */
|
|
94899
|
+
402: {
|
|
94900
|
+
headers: {
|
|
94901
|
+
[name: string]: unknown;
|
|
94902
|
+
};
|
|
94903
|
+
content: {
|
|
94904
|
+
/**
|
|
94905
|
+
* @example {
|
|
94906
|
+
* "error": {
|
|
94907
|
+
* "code": "ENTITLEMENT_NOT_ACTIVE",
|
|
94908
|
+
* "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
|
|
94909
|
+
* "details": {
|
|
94910
|
+
* "required": [
|
|
94911
|
+
* "vitrina_ads"
|
|
94912
|
+
* ],
|
|
94913
|
+
* "active": [],
|
|
94914
|
+
* "feature": "vitrina_ads",
|
|
94915
|
+
* "entitlement_state": "off"
|
|
94916
|
+
* }
|
|
94917
|
+
* }
|
|
94918
|
+
* }
|
|
94919
|
+
*/
|
|
94920
|
+
"application/json": components["schemas"]["Error"];
|
|
94921
|
+
};
|
|
94922
|
+
};
|
|
93459
94923
|
/** @description Forbidden */
|
|
93460
94924
|
403: {
|
|
93461
94925
|
headers: {
|
|
@@ -93474,21 +94938,54 @@ interface paths {
|
|
|
93474
94938
|
"application/json": components["schemas"]["Error"];
|
|
93475
94939
|
};
|
|
93476
94940
|
};
|
|
93477
|
-
/** @description
|
|
94941
|
+
/** @description `handoff_mismatch` (a stale tab), `not_selecting` (no choice owed), `account_connected_elsewhere` (the picker stays open) or `selection_conflict` (connect again). */
|
|
93478
94942
|
409: {
|
|
93479
94943
|
headers: {
|
|
93480
94944
|
[name: string]: unknown;
|
|
93481
94945
|
};
|
|
93482
94946
|
content: {
|
|
94947
|
+
/**
|
|
94948
|
+
* @example {
|
|
94949
|
+
* "error": {
|
|
94950
|
+
* "code": "not_selecting",
|
|
94951
|
+
* "message": "Esta conexión no está esperando que elijas una subcuenta. Actualiza la página."
|
|
94952
|
+
* }
|
|
94953
|
+
* }
|
|
94954
|
+
*/
|
|
93483
94955
|
"application/json": components["schemas"]["Error"];
|
|
93484
94956
|
};
|
|
93485
94957
|
};
|
|
93486
|
-
/** @description
|
|
94958
|
+
/** @description `selection_expired` — the picker’s 60-minute window ended; connect again. */
|
|
93487
94959
|
410: {
|
|
93488
94960
|
headers: {
|
|
93489
94961
|
[name: string]: unknown;
|
|
93490
94962
|
};
|
|
93491
94963
|
content: {
|
|
94964
|
+
/**
|
|
94965
|
+
* @example {
|
|
94966
|
+
* "error": {
|
|
94967
|
+
* "code": "selection_expired",
|
|
94968
|
+
* "message": "Pasó demasiado tiempo para elegir la subcuenta. Vuelve a conectar GoHighLevel."
|
|
94969
|
+
* }
|
|
94970
|
+
* }
|
|
94971
|
+
*/
|
|
94972
|
+
"application/json": components["schemas"]["Error"];
|
|
94973
|
+
};
|
|
94974
|
+
};
|
|
94975
|
+
/** @description `candidate_unavailable` — the account is no longer reachable; the next card read refreshes the list. */
|
|
94976
|
+
422: {
|
|
94977
|
+
headers: {
|
|
94978
|
+
[name: string]: unknown;
|
|
94979
|
+
};
|
|
94980
|
+
content: {
|
|
94981
|
+
/**
|
|
94982
|
+
* @example {
|
|
94983
|
+
* "error": {
|
|
94984
|
+
* "code": "candidate_unavailable",
|
|
94985
|
+
* "message": "Esa subcuenta ya no está disponible. Elige otra de la lista."
|
|
94986
|
+
* }
|
|
94987
|
+
* }
|
|
94988
|
+
*/
|
|
93492
94989
|
"application/json": components["schemas"]["Error"];
|
|
93493
94990
|
};
|
|
93494
94991
|
};
|
|
@@ -93509,40 +95006,38 @@ interface paths {
|
|
|
93509
95006
|
patch?: never;
|
|
93510
95007
|
trace?: never;
|
|
93511
95008
|
};
|
|
93512
|
-
"/integrations/
|
|
95009
|
+
"/integrations/connections/{provider}/disconnect": {
|
|
93513
95010
|
parameters: {
|
|
93514
95011
|
query?: never;
|
|
93515
95012
|
header?: never;
|
|
93516
95013
|
path?: never;
|
|
93517
95014
|
cookie?: never;
|
|
93518
95015
|
};
|
|
95016
|
+
get?: never;
|
|
95017
|
+
put?: never;
|
|
93519
95018
|
/**
|
|
93520
|
-
*
|
|
93521
|
-
* @description
|
|
95019
|
+
* Disconnect a provider
|
|
95020
|
+
* @description Disconnects the account at the provider and settles the card `disconnected` with `reason.code: "disconnected_by_user"`, keeping `last_account` so the card can say what was disconnected. A connect in flight with nothing connected yet is cancelled locally. **Idempotent:** a card with nothing live answers as it stands.
|
|
93522
95021
|
*
|
|
93523
|
-
*
|
|
93524
|
-
*
|
|
93525
|
-
* `data.state` is `not_connected` in TWO cases, told apart by an optional `reason`:
|
|
93526
|
-
* * no `reason` — the tenant has never connected a Meta Ads account (the integration row is missing or not `connected`).
|
|
93527
|
-
* * `reason: "whatsapp_not_connected"` — Meta Ads may be connected, but the tenant holds no `whatsapp_cloud` account carrying an partner token, so there is no scope to list ads under.
|
|
95022
|
+
* 409 `sync_in_flight` — the provider is mid-sync; nothing changed, try again in a few minutes. 502 `disconnect_refused` — the provider refused; nothing changed. 502 `UPSTREAM_ERROR` — the provider could not be reached; nothing changed.
|
|
93528
95023
|
*
|
|
93529
|
-
*
|
|
93530
|
-
*
|
|
93531
|
-
* 502 `UPSTREAM_ERROR` on a provider 5xx, timeout, or a response shape this route does not recognise. 502 `partner_token_invalid` when the provider answers 401 on the WhatsApp partner token — that token is never auto-rotated; the dealer must reconnect WhatsApp.
|
|
95024
|
+
* Requires `integrations:write`.
|
|
93532
95025
|
*/
|
|
93533
|
-
|
|
95026
|
+
post: {
|
|
93534
95027
|
parameters: {
|
|
93535
|
-
query?:
|
|
93536
|
-
|
|
93537
|
-
|
|
95028
|
+
query?: never;
|
|
95029
|
+
header?: {
|
|
95030
|
+
/** @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. */
|
|
95031
|
+
"Idempotency-Key"?: string;
|
|
95032
|
+
};
|
|
95033
|
+
path: {
|
|
95034
|
+
provider: "gohighlevel" | "mercadopago";
|
|
93538
95035
|
};
|
|
93539
|
-
header?: never;
|
|
93540
|
-
path?: never;
|
|
93541
95036
|
cookie?: never;
|
|
93542
95037
|
};
|
|
93543
95038
|
requestBody?: never;
|
|
93544
95039
|
responses: {
|
|
93545
|
-
/** @description
|
|
95040
|
+
/** @description The disconnected card */
|
|
93546
95041
|
200: {
|
|
93547
95042
|
headers: {
|
|
93548
95043
|
[name: string]: unknown;
|
|
@@ -93551,50 +95046,38 @@ interface paths {
|
|
|
93551
95046
|
/**
|
|
93552
95047
|
* @example {
|
|
93553
95048
|
* "data": {
|
|
93554
|
-
* "
|
|
93555
|
-
* "
|
|
93556
|
-
*
|
|
93557
|
-
*
|
|
93558
|
-
*
|
|
93559
|
-
*
|
|
93560
|
-
*
|
|
93561
|
-
*
|
|
93562
|
-
*
|
|
93563
|
-
*
|
|
93564
|
-
*
|
|
93565
|
-
*
|
|
93566
|
-
*
|
|
93567
|
-
*
|
|
93568
|
-
*
|
|
93569
|
-
*
|
|
93570
|
-
*
|
|
93571
|
-
*
|
|
93572
|
-
*
|
|
93573
|
-
*
|
|
93574
|
-
*
|
|
93575
|
-
*
|
|
93576
|
-
*
|
|
93577
|
-
*
|
|
93578
|
-
*
|
|
93579
|
-
*
|
|
93580
|
-
*
|
|
93581
|
-
* "landing_screen_type": "welcome_message"
|
|
93582
|
-
* },
|
|
93583
|
-
* "greeting_status": "present",
|
|
93584
|
-
* "checks": {
|
|
93585
|
-
* "destination_connected": true,
|
|
93586
|
-
* "greeting_configured": true
|
|
93587
|
-
* },
|
|
93588
|
-
* "last_synced_at": "2026-09-23T14:00:00.000Z"
|
|
93589
|
-
* }
|
|
93590
|
-
* ],
|
|
93591
|
-
* "next_cursor": null,
|
|
93592
|
-
* "last_synced_at": "2026-09-23T14:00:00.000Z"
|
|
95049
|
+
* "provider": "gohighlevel",
|
|
95050
|
+
* "display_name": "GoHighLevel",
|
|
95051
|
+
* "category": "crm",
|
|
95052
|
+
* "description": "Trae los formularios y las oportunidades de tu CRM para seguir cada lead hasta la venta.",
|
|
95053
|
+
* "last_account": {
|
|
95054
|
+
* "external_id": "loc_8XkP2qR5tV",
|
|
95055
|
+
* "name": "Agencia Ejemplo"
|
|
95056
|
+
* },
|
|
95057
|
+
* "last_attempt": null,
|
|
95058
|
+
* "disconnected_at": "2026-09-28T10:00:00.000Z",
|
|
95059
|
+
* "addon_active": true,
|
|
95060
|
+
* "state": "disconnected",
|
|
95061
|
+
* "state_label": "Desconectado",
|
|
95062
|
+
* "account": null,
|
|
95063
|
+
* "reason": {
|
|
95064
|
+
* "code": "disconnected_by_user",
|
|
95065
|
+
* "label": "Desconectaste GoHighLevel.",
|
|
95066
|
+
* "retryable": true
|
|
95067
|
+
* },
|
|
95068
|
+
* "next_step": {
|
|
95069
|
+
* "action": "connect",
|
|
95070
|
+
* "label": "Conectar"
|
|
95071
|
+
* },
|
|
95072
|
+
* "attempt": null,
|
|
95073
|
+
* "connected_at": null,
|
|
95074
|
+
* "last_synced_at": "2026-09-27T15:20:00.000Z",
|
|
95075
|
+
* "updated_at": "2026-09-28T10:00:00.000Z"
|
|
93593
95076
|
* }
|
|
93594
95077
|
* }
|
|
93595
95078
|
*/
|
|
93596
95079
|
"application/json": {
|
|
93597
|
-
data: components["schemas"]["
|
|
95080
|
+
data: components["schemas"]["ProviderConnection"];
|
|
93598
95081
|
};
|
|
93599
95082
|
};
|
|
93600
95083
|
};
|
|
@@ -93616,6 +95099,31 @@ interface paths {
|
|
|
93616
95099
|
"application/json": components["schemas"]["Error"];
|
|
93617
95100
|
};
|
|
93618
95101
|
};
|
|
95102
|
+
/** @description The Vitrina Ads add-on is not active and nothing is connected (or in flight) for this provider. `error.code` is `ENTITLEMENT_NOT_ACTIVE`, `error.details.feature` is `vitrina_ads`. A connection that outlived the add-on is never refused here: it stays readable, finishable and disconnectable. */
|
|
95103
|
+
402: {
|
|
95104
|
+
headers: {
|
|
95105
|
+
[name: string]: unknown;
|
|
95106
|
+
};
|
|
95107
|
+
content: {
|
|
95108
|
+
/**
|
|
95109
|
+
* @example {
|
|
95110
|
+
* "error": {
|
|
95111
|
+
* "code": "ENTITLEMENT_NOT_ACTIVE",
|
|
95112
|
+
* "message": "El complemento Vitrina Ads no está activo en este espacio de trabajo.",
|
|
95113
|
+
* "details": {
|
|
95114
|
+
* "required": [
|
|
95115
|
+
* "vitrina_ads"
|
|
95116
|
+
* ],
|
|
95117
|
+
* "active": [],
|
|
95118
|
+
* "feature": "vitrina_ads",
|
|
95119
|
+
* "entitlement_state": "off"
|
|
95120
|
+
* }
|
|
95121
|
+
* }
|
|
95122
|
+
* }
|
|
95123
|
+
*/
|
|
95124
|
+
"application/json": components["schemas"]["Error"];
|
|
95125
|
+
};
|
|
95126
|
+
};
|
|
93619
95127
|
/** @description Forbidden */
|
|
93620
95128
|
403: {
|
|
93621
95129
|
headers: {
|
|
@@ -93654,8 +95162,6 @@ interface paths {
|
|
|
93654
95162
|
};
|
|
93655
95163
|
};
|
|
93656
95164
|
};
|
|
93657
|
-
put?: never;
|
|
93658
|
-
post?: never;
|
|
93659
95165
|
delete?: never;
|
|
93660
95166
|
options?: never;
|
|
93661
95167
|
head?: never;
|
|
@@ -95153,7 +96659,13 @@ interface paths {
|
|
|
95153
96659
|
* "verdict": "healthy_tracking",
|
|
95154
96660
|
* "tracking_healthy": true,
|
|
95155
96661
|
* "coverage_interpretation": "La mayoría de las ventas llegan con su origen publicitario.",
|
|
95156
|
-
* "missing": []
|
|
96662
|
+
* "missing": [],
|
|
96663
|
+
* "tracker": {
|
|
96664
|
+
* "status": "live",
|
|
96665
|
+
* "web_touches": 1842,
|
|
96666
|
+
* "last_web_touch": "2026-08-31T21:14:00Z",
|
|
96667
|
+
* "fresh": true
|
|
96668
|
+
* }
|
|
95157
96669
|
* },
|
|
95158
96670
|
* "traceable_roas_trend": {
|
|
95159
96671
|
* "recent_roas": 3.4,
|
|
@@ -96289,7 +97801,7 @@ interface paths {
|
|
|
96289
97801
|
*
|
|
96290
97802
|
* `window` (Creativos only) derives the rail on the same rolling creatives window as `GET /ads/creatives`; pass the same `window` to preview.
|
|
96291
97803
|
*
|
|
96292
|
-
* A `key` is `<kind>:<target external id>:<YYYY-MM-DD>` and is stable for the day. Dismissed actions stay on the list with `dismissed_until` set, sorted last. `include=adset_duplicate_swap` also lists the duplicate-and-swap actions (hidden by default).
|
|
97804
|
+
* A `key` is `<kind>:<target external id>:<YYYY-MM-DD>` and is stable for the day. Dismissed actions stay on the list with `dismissed_until` set, sorted last. `include=adset_duplicate_swap` also lists the duplicate-and-swap actions (hidden by default). `include=campaign_pause` (Campañas, Resumen) marks a client that renders the whole-campaign pause card (`campaign_pause`: one atomic change in Meta, undone with «Reanudar»). **Not offered yet** — its eligibility rule is pending — so today the list never contains it, with or without the include, and a campaign that spent with no results keeps the per-ad cards.
|
|
96293
97805
|
*
|
|
96294
97806
|
* Card state machine (client): `proposed → previewing → confirming → running → done | failed | refused → (done) reverted`; `dismissed` for 7 days; `simulated` replaces `done` in sample mode.
|
|
96295
97807
|
*/
|
|
@@ -96302,8 +97814,8 @@ interface paths {
|
|
|
96302
97814
|
to: string;
|
|
96303
97815
|
/** @description `creativos` only: the creatives window the rail is derived for — the same rolling lookback as `GET /ads/creatives?window=`, so a card’s figures (the worn-out ad’s spend) match the gallery. Defaults to `28d`. Sent with any other screen → 400. */
|
|
96304
97816
|
window?: "7d" | "14d" | "28d" | "lifetime";
|
|
96305
|
-
/** @description `adset_duplicate_swap` also lists the duplicate-and-swap actions (Salud). Hidden by default: it rebuilds an ad set (new id, learning reset) and is offered as the alternative after a `promoted_object_frozen` refusal. */
|
|
96306
|
-
include?: "adset_duplicate_swap";
|
|
97817
|
+
/** @description `adset_duplicate_swap` also lists the duplicate-and-swap actions (Salud). Hidden by default: it rebuilds an ad set (new id, learning reset) and is offered as the alternative after a `promoted_object_frozen` refusal. `campaign_pause` (Campañas, Resumen): the client renders the whole-campaign pause card. Not offered yet (its rule is pending): accepted, and the list does not contain the card today. */
|
|
97818
|
+
include?: "adset_duplicate_swap" | "campaign_pause";
|
|
96307
97819
|
/** @description `1` serves the deterministic sample dataset («Ver con datos de ejemplo»): same shapes, invented but internally consistent figures, no entitlement required (the scope still is). A sandbox workspace is always served the sample, with or without this parameter. */
|
|
96308
97820
|
sample?: "1" | "true";
|
|
96309
97821
|
};
|
|
@@ -96591,9 +98103,9 @@ interface paths {
|
|
|
96591
98103
|
put?: never;
|
|
96592
98104
|
/**
|
|
96593
98105
|
* Preview an action before confirming it
|
|
96594
|
-
* @description Reads the target’s live state and returns what will change (`rows`: before → after), the warnings, and — for a duplicate-and-swap or a URL-parameter fix — the consent lines the owner must accept. A `url_tags_fix` preview lists `untagged_ads` («{n} → 0») first, then one row per ad (`ad:<id>`): its current parameters → exactly what it gets; an ad changed in Meta after the preview is skipped at execute, never rewritten blind. It also records ONE single-use approval bound to the caller, the action and its exact parameters, valid for 10 minutes (`expires_at`): `preview_id` is what `execute` spends. No engine write happens here.
|
|
98106
|
+
* @description Reads the target’s live state and returns what will change (`rows`: before → after), the warnings, and — for a duplicate-and-swap or a URL-parameter fix — the consent lines the owner must accept. A `url_tags_fix` preview lists `untagged_ads` («{n} → 0») first, then one row per ad (`ad:<id>`): its current parameters → exactly what it gets; an ad changed in Meta after the preview is skipped at execute, never rewritten blind. A `campaign_pause` preview reads the campaign live ONCE and returns everything its sheet and card draw: `summary` («Pausar «{campaign}» · detiene {n} anuncios · ~$X al día»), `campaign` (status, the ads it stops, the mean daily spend and the budget as exact decimal strings with their currency, and where the budget lives) and the rows `status`, `delivering_ads`, `avg_daily_spend`, `budget`, plus its consent. It also records ONE single-use approval bound to the caller, the action and its exact parameters, valid for 10 minutes (`expires_at`): `preview_id` is what `execute` spends. No engine write happens here.
|
|
96595
98107
|
*
|
|
96596
|
-
* 409 `ADS_ACTION_NOT_AVAILABLE` when the action is no longer on today’s list (or is a `nav` card, which has nothing to execute).
|
|
98108
|
+
* 409 `ADS_ACTION_NOT_AVAILABLE` when the action is no longer on today’s list (or is a `nav` card, which has nothing to execute). A `campaign_pause` key answers it with `details.reason: not_offered` while that action is not offered; once it is, it also answers it when the live read says the pause cannot run now — `details.reason`: `not_active` (already paused), `not_pausable` (archived or deleted), `campaign_not_found`, `meta_connection_missing`, `permission_gap`, `reconnect_required`, `not_available` (any other refusal of the read), `too_recent` (less than 7 complete days of spend) — with `details.explanation`, Spanish copy for the owner; an already-paused, archived or missing campaign also hides the card for 7 days, and a too-recent one until the day it can be judged. 503 `ADS_ACTION_READ_UNAVAILABLE` (`details.reason: meta_unavailable`) when the campaign could not be read right now — retry in a moment.
|
|
96597
98109
|
*/
|
|
96598
98110
|
post: {
|
|
96599
98111
|
parameters: {
|
|
@@ -96754,6 +98266,15 @@ interface paths {
|
|
|
96754
98266
|
"application/json": components["schemas"]["Error"];
|
|
96755
98267
|
};
|
|
96756
98268
|
};
|
|
98269
|
+
/** @description `campaign_pause` only: the campaign could not be read right now (no answer, an upstream error or a rate limit). `error.code` is `ADS_ACTION_READ_UNAVAILABLE`, `details.reason: meta_unavailable`, `details.explanation` Spanish copy for the owner. Nothing was recorded; retry in a moment. */
|
|
98270
|
+
503: {
|
|
98271
|
+
headers: {
|
|
98272
|
+
[name: string]: unknown;
|
|
98273
|
+
};
|
|
98274
|
+
content: {
|
|
98275
|
+
"application/json": components["schemas"]["Error"];
|
|
98276
|
+
};
|
|
98277
|
+
};
|
|
96757
98278
|
};
|
|
96758
98279
|
};
|
|
96759
98280
|
delete?: never;
|
|
@@ -96777,11 +98298,13 @@ interface paths {
|
|
|
96777
98298
|
*
|
|
96778
98299
|
* 409 `ADS_ACTION_REPLAY_BLOCKED` when the approval cannot be spent — `details.reason` is `expired` (preview older than 10 minutes), `consumed` (already confirmed, e.g. from another tab), `not_found` or `binding_mismatch` (another person’s preview, or another action — incl. a real preview sent with `sample: true`). In sample mode nothing reaches the engine: the execution is born `succeeded` with `simulated: true`, and only a sample preview can be spent.
|
|
96779
98300
|
*
|
|
96780
|
-
* **
|
|
98301
|
+
* **`campaign_pause`**, **duplicate-and-swap** and **`url_tags_fix`** need the owner’s acceptance of the preview’s `consent_terms` (the verbatim consent text): send `consent: { version, text_hash, accepted_at? }`. Missing, different or older than 24 h → 409 `ADS_ACTION_CONSENT_REQUIRED` (`details.reason` missing|mismatch|stale, `details.consent` = the current version and hash) — nothing is spent and nothing reaches the engine.
|
|
96781
98302
|
*
|
|
96782
98303
|
* If the job cannot be queued the answer is still 202, with `status: failed`: the execution exists and says why (`error.code: queue_unavailable`).
|
|
96783
98304
|
*
|
|
96784
98305
|
* A `url_tags_fix` corrects each ad on its own: `outcome.summary` reads «{k} de {n} anuncios corregidos», `outcome.partial` is true when k < n, and `outcome.ads[]` says what happened to each ad. None corrected → `failed`/`refused` with the first ad’s reason, still with `outcome.ads[]`.
|
|
98306
|
+
*
|
|
98307
|
+
* A `campaign_pause` is ONE change in Meta. Each execution is its own request: a second confirm (another tab, an agent) finds the campaign already paused and answers `outcome.engine_outcome: no_change` — nothing written, no journal line, nothing to undo. Otherwise `engine_outcome` is `applied`, or `replayed` (a retry of this same execution); `outcome.affected_ads_count` is how many ads stopped.
|
|
96785
98308
|
*/
|
|
96786
98309
|
post: {
|
|
96787
98310
|
parameters: {
|
|
@@ -96810,7 +98333,7 @@ interface paths {
|
|
|
96810
98333
|
*/
|
|
96811
98334
|
preview_id: string;
|
|
96812
98335
|
sample?: boolean;
|
|
96813
|
-
/** @description Required whenever the preview returned `consent_terms` (a duplicate-and-swap, a URL-parameter fix `url_tags_fix`, «Enviar a Meta»'s `send_setup` and `send_dataset`, and a `send_stage` off / `send_stop` that stops an event active ad sets optimise on), ignored otherwise: the owner's acceptance of `consent_terms` — echo its `version` and `text_hash`. The accepting person is always the caller. */
|
|
98336
|
+
/** @description Required whenever the preview returned `consent_terms` (a campaign pause `campaign_pause`, a duplicate-and-swap, a URL-parameter fix `url_tags_fix`, «Enviar a Meta»'s `send_setup` and `send_dataset`, and a `send_stage` off / `send_stop` that stops an event active ad sets optimise on), ignored otherwise: the owner's acceptance of `consent_terms` — echo its `version` and `text_hash`. The accepting person is always the caller. */
|
|
96814
98337
|
consent?: {
|
|
96815
98338
|
version: string;
|
|
96816
98339
|
text_hash: string;
|
|
@@ -97219,7 +98742,7 @@ interface paths {
|
|
|
97219
98742
|
};
|
|
97220
98743
|
/**
|
|
97221
98744
|
* The status of an action execution
|
|
97222
|
-
* @description `queued → running → succeeded | failed | refused`; a succeeded execution becomes `rolled_back` when its rollback succeeds. `error.reason` is one of `promoted_object_frozen` (Meta froze the ad set’s conversion — the duplicate-and-swap is the alternative), `reconnect_required`, `permission_gap` (Meta connected without permission to manage ads — reconnect keeping it), `rate_limited`, `not_reversible`, `forbidden` (no person could be put on the record for the change — not a Meta grant problem), `consent_required` (the duplicate-and-swap consent is missing or stale — preview again), `engine_error` (incl. `code: budget_change_out_of_bounds` — outside the ±50 % allowed per change — `code: not_active` and `code: no_recommendation`). `error.message` is Spanish copy ready for the card. `target` is what the action touched (with `campaign_name`, the campaign the card named, on an ad-set budget change).
|
|
98745
|
+
* @description `queued → running → succeeded | failed | refused`; a succeeded execution becomes `rolled_back` when its rollback succeeds. `error.reason` is one of `promoted_object_frozen` (Meta froze the ad set’s conversion — the duplicate-and-swap is the alternative), `reconnect_required`, `permission_gap` (Meta connected without permission to manage ads — reconnect keeping it), `rate_limited`, `not_reversible`, `forbidden` (no person could be put on the record for the change — not a Meta grant problem), `consent_required` (the duplicate-and-swap consent is missing or stale — preview again), `engine_error` (incl. `code: budget_change_out_of_bounds` — outside the ±50 % allowed per change — `code: not_active` and `code: no_recommendation`). Campaign pause codes: `campaign_not_found` / `campaign_not_pausable` (archived or deleted — never written) / `meta_refused` (`engine_error`), `campaign_not_resumable` (`not_reversible`), a dead Meta token → `reconnect_required`, `meta_permission_denied` (`permission_gap` — Meta refused for a missing permission), `applied_by_not_allowed` (`forbidden`), `meta_rate_limited` (`rate_limited`, retried first). `error.message` is Spanish copy ready for the card. `target` is what the action touched (with `campaign_name`, the campaign the card named, on an ad-set budget change).
|
|
97223
98746
|
*/
|
|
97224
98747
|
get: {
|
|
97225
98748
|
parameters: {
|
|
@@ -97385,7 +98908,7 @@ interface paths {
|
|
|
97385
98908
|
put?: never;
|
|
97386
98909
|
/**
|
|
97387
98910
|
* Undo an executed action
|
|
97388
|
-
* @description Queues the engine’s rollback of a `succeeded` execution with `rollback_available: true` and answers the NEW execution (`rollback_of` = the original). The engine restores the pre-change state only while the object still carries what the action wrote; otherwise the rollback is `refused` with `reason: not_reversible` (`code: state_drifted`). A `url_tags_fix` is undone ad by ad (each ad back on its previous parameters): an ad changed in Meta since is left alone (final), an ad whose undo got no answer stays pending — the original keeps `rollback_available: true` and the next rollback sends only those ads; the original reads `rolled_back` once nothing is pending. **`Idempotency-Key` is required.** 409 `ADS_ACTION_NOT_REVERSIBLE` when the execution has nothing to undo.
|
|
98911
|
+
* @description Queues the engine’s rollback of a `succeeded` execution with `rollback_available: true` and answers the NEW execution (`rollback_of` = the original). The engine restores the pre-change state only while the object still carries what the action wrote; otherwise the rollback is `refused` with `reason: not_reversible` (`code: state_drifted`). A `url_tags_fix` is undone ad by ad (each ad back on its previous parameters): an ad changed in Meta since is left alone (final), an ad whose undo got no answer stays pending — the original keeps `rollback_available: true` and the next rollback sends only those ads; the original reads `rolled_back` once nothing is pending. A `campaign_pause` is undone with «Reanudar»: one resume in Meta, with a fresh key per request; ads that were paused on their own stay paused. A campaign already active answers `outcome.engine_outcome: no_change` (the pause is then no longer undoable, never marked as undone by Vitrina); an archived or deleted one is `refused` `not_reversible` (`code: campaign_not_resumable`), and so is one paused again by someone else since (`code: paused_since`): «Reanudar» only ever undoes this pause. **`Idempotency-Key` is required.** 409 `ADS_ACTION_NOT_REVERSIBLE` when the execution has nothing to undo.
|
|
97389
98912
|
*/
|
|
97390
98913
|
post: {
|
|
97391
98914
|
parameters: {
|
|
@@ -98217,7 +99740,24 @@ interface paths {
|
|
|
98217
99740
|
* }
|
|
98218
99741
|
* },
|
|
98219
99742
|
* "credited_weight": 1,
|
|
98220
|
-
* "touch_count": 3
|
|
99743
|
+
* "touch_count": 3,
|
|
99744
|
+
* "origin": {
|
|
99745
|
+
* "platform": "whatsapp",
|
|
99746
|
+
* "external_id": "120211000000000101",
|
|
99747
|
+
* "name": "Reel · Antes y después",
|
|
99748
|
+
* "ad_name": "Reel · Antes y después",
|
|
99749
|
+
* "headline": "Evaluación sin costo",
|
|
99750
|
+
* "campaign": {
|
|
99751
|
+
* "external_id": "120211000000000001",
|
|
99752
|
+
* "name": "Ortodoncia invisible · Septiembre"
|
|
99753
|
+
* },
|
|
99754
|
+
* "thumbnail_url": null,
|
|
99755
|
+
* "media_archived": false,
|
|
99756
|
+
* "first_message_at": "2026-09-20T13:02:30.000Z",
|
|
99757
|
+
* "matches_credit": true
|
|
99758
|
+
* },
|
|
99759
|
+
* "origin_source": "engine",
|
|
99760
|
+
* "attribution": "credited"
|
|
98221
99761
|
* },
|
|
98222
99762
|
* {
|
|
98223
99763
|
* "id": "01926f3a-1b2c-7d3e-8f40-5a6b7c8d9e0f",
|
|
@@ -98234,7 +99774,21 @@ interface paths {
|
|
|
98234
99774
|
* },
|
|
98235
99775
|
* "ad": null,
|
|
98236
99776
|
* "credited_weight": null,
|
|
98237
|
-
* "touch_count": null
|
|
99777
|
+
* "touch_count": null,
|
|
99778
|
+
* "origin": {
|
|
99779
|
+
* "platform": "instagram",
|
|
99780
|
+
* "external_id": "120211000000000205",
|
|
99781
|
+
* "name": "Limpieza facial",
|
|
99782
|
+
* "ad_name": null,
|
|
99783
|
+
* "headline": "Limpieza facial",
|
|
99784
|
+
* "campaign": null,
|
|
99785
|
+
* "thumbnail_url": null,
|
|
99786
|
+
* "media_archived": false,
|
|
99787
|
+
* "first_message_at": "2026-09-22T17:40:05.000Z",
|
|
99788
|
+
* "matches_credit": null
|
|
99789
|
+
* },
|
|
99790
|
+
* "origin_source": "conversation",
|
|
99791
|
+
* "attribution": "pending"
|
|
98238
99792
|
* }
|
|
98239
99793
|
* ],
|
|
98240
99794
|
* "meta": {
|
|
@@ -98456,6 +100010,31 @@ interface paths {
|
|
|
98456
100010
|
* "channel": "meta"
|
|
98457
100011
|
* },
|
|
98458
100012
|
* {
|
|
100013
|
+
* "stage": null,
|
|
100014
|
+
* "detail": "Ortodoncia invisible · Septiembre",
|
|
100015
|
+
* "credited": false,
|
|
100016
|
+
* "join_method": "ctwa_referral",
|
|
100017
|
+
* "click_id_kind": "ctwa_clid",
|
|
100018
|
+
* "ad": {
|
|
100019
|
+
* "external_id": "120211000000000101",
|
|
100020
|
+
* "name": "Reel · Antes y después",
|
|
100021
|
+
* "ad_set_name": "Mujeres 30-45 · Providencia",
|
|
100022
|
+
* "campaign": {
|
|
100023
|
+
* "external_id": "120211000000000100",
|
|
100024
|
+
* "name": "Ortodoncia invisible · Septiembre"
|
|
100025
|
+
* },
|
|
100026
|
+
* "creative_thumbnail_url": null
|
|
100027
|
+
* },
|
|
100028
|
+
* "value": null,
|
|
100029
|
+
* "current": false,
|
|
100030
|
+
* "id": "7d7d7d7d-1111-4222-8333-444455556666",
|
|
100031
|
+
* "kind": "chat",
|
|
100032
|
+
* "origin": "vitrina",
|
|
100033
|
+
* "label": "Mensaje por el anuncio «Reel · Antes y después»",
|
|
100034
|
+
* "at": "2026-09-20T13:02:30.000Z",
|
|
100035
|
+
* "channel": "whatsapp"
|
|
100036
|
+
* },
|
|
100037
|
+
* {
|
|
98459
100038
|
* "stage": "lead_created",
|
|
98460
100039
|
* "detail": "Por WhatsApp",
|
|
98461
100040
|
* "credited": false,
|
|
@@ -108794,6 +110373,151 @@ interface paths {
|
|
|
108794
110373
|
patch?: never;
|
|
108795
110374
|
trace?: never;
|
|
108796
110375
|
};
|
|
110376
|
+
"/whatsapp-templates/category-check": {
|
|
110377
|
+
parameters: {
|
|
110378
|
+
query?: never;
|
|
110379
|
+
header?: never;
|
|
110380
|
+
path?: never;
|
|
110381
|
+
cookie?: never;
|
|
110382
|
+
};
|
|
110383
|
+
get?: never;
|
|
110384
|
+
put?: never;
|
|
110385
|
+
/**
|
|
110386
|
+
* Predict whether Meta will reclassify a UTILITY draft as MARKETING
|
|
110387
|
+
* @description Jev-calibrated preview the template editor calls before submit (#2972). Meta silently reclassifies UTILITY templates as MARKETING at review time; this warns before that happens instead of after. `category` other than `UTILITY` always answers `applicable: false` — Meta’s reclassification only runs that one direction, so nothing is asked. Never changes what gets submitted and never writes to the Jev ledger (a preview is not an acted-on decision — the actual submission is what gets ledgered and later graded against Meta’s verdict). `cause` is a deterministic guess (never Jev’s own answer) set only when `likely_marketing` is true.
|
|
110388
|
+
*/
|
|
110389
|
+
post: {
|
|
110390
|
+
parameters: {
|
|
110391
|
+
query?: never;
|
|
110392
|
+
header?: {
|
|
110393
|
+
/** @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. */
|
|
110394
|
+
"Idempotency-Key"?: string;
|
|
110395
|
+
};
|
|
110396
|
+
path?: never;
|
|
110397
|
+
cookie?: never;
|
|
110398
|
+
};
|
|
110399
|
+
requestBody?: {
|
|
110400
|
+
content: {
|
|
110401
|
+
/**
|
|
110402
|
+
* @example {
|
|
110403
|
+
* "category": "UTILITY",
|
|
110404
|
+
* "body_text": "Hola {{1}}, ¿sigues interesado en el {{2}}? Si quieres, coordinamos una visita para que lo veas.",
|
|
110405
|
+
* "footer_text": "Autos del Valle"
|
|
110406
|
+
* }
|
|
110407
|
+
*/
|
|
110408
|
+
"application/json": {
|
|
110409
|
+
/** @enum {string} */
|
|
110410
|
+
category: "MARKETING" | "UTILITY" | "AUTHENTICATION";
|
|
110411
|
+
body_text: string;
|
|
110412
|
+
header_text?: string | null;
|
|
110413
|
+
footer_text?: string | null;
|
|
110414
|
+
buttons?: ({
|
|
110415
|
+
/** @enum {string} */
|
|
110416
|
+
type: "QUICK_REPLY";
|
|
110417
|
+
text: string;
|
|
110418
|
+
} | {
|
|
110419
|
+
/** @enum {string} */
|
|
110420
|
+
type: "URL";
|
|
110421
|
+
text: string;
|
|
110422
|
+
/** Format: uri */
|
|
110423
|
+
url: string;
|
|
110424
|
+
/** Format: uri */
|
|
110425
|
+
example?: string;
|
|
110426
|
+
} | {
|
|
110427
|
+
/** @enum {string} */
|
|
110428
|
+
type: "PHONE_NUMBER";
|
|
110429
|
+
text: string;
|
|
110430
|
+
phone_number: string;
|
|
110431
|
+
})[];
|
|
110432
|
+
};
|
|
110433
|
+
};
|
|
110434
|
+
};
|
|
110435
|
+
responses: {
|
|
110436
|
+
/** @description The prediction */
|
|
110437
|
+
200: {
|
|
110438
|
+
headers: {
|
|
110439
|
+
[name: string]: unknown;
|
|
110440
|
+
};
|
|
110441
|
+
content: {
|
|
110442
|
+
/**
|
|
110443
|
+
* @example {
|
|
110444
|
+
* "data": {
|
|
110445
|
+
* "applicable": true,
|
|
110446
|
+
* "likely_marketing": true,
|
|
110447
|
+
* "cause": "promotional_wording"
|
|
110448
|
+
* }
|
|
110449
|
+
* }
|
|
110450
|
+
*/
|
|
110451
|
+
"application/json": {
|
|
110452
|
+
data?: unknown;
|
|
110453
|
+
meta?: {
|
|
110454
|
+
[key: string]: unknown;
|
|
110455
|
+
};
|
|
110456
|
+
};
|
|
110457
|
+
};
|
|
110458
|
+
};
|
|
110459
|
+
/** @description Validation error */
|
|
110460
|
+
400: {
|
|
110461
|
+
headers: {
|
|
110462
|
+
[name: string]: unknown;
|
|
110463
|
+
};
|
|
110464
|
+
content: {
|
|
110465
|
+
"application/json": components["schemas"]["Error"];
|
|
110466
|
+
};
|
|
110467
|
+
};
|
|
110468
|
+
/** @description Unauthorized */
|
|
110469
|
+
401: {
|
|
110470
|
+
headers: {
|
|
110471
|
+
[name: string]: unknown;
|
|
110472
|
+
};
|
|
110473
|
+
content: {
|
|
110474
|
+
"application/json": components["schemas"]["Error"];
|
|
110475
|
+
};
|
|
110476
|
+
};
|
|
110477
|
+
/** @description Forbidden */
|
|
110478
|
+
403: {
|
|
110479
|
+
headers: {
|
|
110480
|
+
[name: string]: unknown;
|
|
110481
|
+
};
|
|
110482
|
+
content: {
|
|
110483
|
+
"application/json": components["schemas"]["Error"];
|
|
110484
|
+
};
|
|
110485
|
+
};
|
|
110486
|
+
/** @description Not found */
|
|
110487
|
+
404: {
|
|
110488
|
+
headers: {
|
|
110489
|
+
[name: string]: unknown;
|
|
110490
|
+
};
|
|
110491
|
+
content: {
|
|
110492
|
+
"application/json": components["schemas"]["Error"];
|
|
110493
|
+
};
|
|
110494
|
+
};
|
|
110495
|
+
/** @description Conflict (incl. Idempotency-Key reuse with different body) */
|
|
110496
|
+
409: {
|
|
110497
|
+
headers: {
|
|
110498
|
+
[name: string]: unknown;
|
|
110499
|
+
};
|
|
110500
|
+
content: {
|
|
110501
|
+
"application/json": components["schemas"]["Error"];
|
|
110502
|
+
};
|
|
110503
|
+
};
|
|
110504
|
+
/** @description Rate limited */
|
|
110505
|
+
429: {
|
|
110506
|
+
headers: {
|
|
110507
|
+
[name: string]: unknown;
|
|
110508
|
+
};
|
|
110509
|
+
content: {
|
|
110510
|
+
"application/json": components["schemas"]["Error"];
|
|
110511
|
+
};
|
|
110512
|
+
};
|
|
110513
|
+
};
|
|
110514
|
+
};
|
|
110515
|
+
delete?: never;
|
|
110516
|
+
options?: never;
|
|
110517
|
+
head?: never;
|
|
110518
|
+
patch?: never;
|
|
110519
|
+
trace?: never;
|
|
110520
|
+
};
|
|
108797
110521
|
"/whatsapp-templates/{id}/param-meta": {
|
|
108798
110522
|
parameters: {
|
|
108799
110523
|
query?: never;
|
|
@@ -118859,11 +120583,11 @@ interface components {
|
|
|
118859
120583
|
stage_count: number;
|
|
118860
120584
|
/** @description Clinics: the Purchase volume of the first payment, counted before the switch too. `null` outside clinics or when it could not be read. */
|
|
118861
120585
|
first_payment_candidates: {
|
|
118862
|
-
/** @description First payments of accepted plans over the last 28 days in Vitrina’s payment ledger — what reaches Meta as Purchase once switched. */
|
|
120586
|
+
/** @description First payments of accepted plans over the last 28 days — in Vitrina’s payment ledger and in the clinic system’s mirror, one per sale — what reaches Meta as Purchase once switched. */
|
|
118863
120587
|
count_28d: number;
|
|
118864
120588
|
/** @description `count_28d / 4`, one decimal. */
|
|
118865
120589
|
weekly_28d: number;
|
|
118866
|
-
/** @description
|
|
120590
|
+
/** @description Of `count_28d`, the first payments claimed from the clinic system’s mirror (they reach Meta like the ledger’s). `null` without a mirror opt-in. */
|
|
118867
120591
|
mirror_count_28d: number | null;
|
|
118868
120592
|
mirror_weekly_28d: number | null;
|
|
118869
120593
|
} | null;
|
|
@@ -119171,6 +120895,107 @@ interface components {
|
|
|
119171
120895
|
last_synced_at: string | null;
|
|
119172
120896
|
};
|
|
119173
120897
|
MetaAdsAdsResponse: components["schemas"]["MetaAdsAdsNotConnected"] | components["schemas"]["MetaAdsAdsConnected"];
|
|
120898
|
+
/** @description The connected account. Present on `connected` and `needs_reconnect` (the card must name what needs reconnecting). */
|
|
120899
|
+
ProviderConnectionAccount: {
|
|
120900
|
+
/** @description The provider’s own id for the account (GoHighLevel location id, Mercado Pago user id). Opaque; relayed verbatim. */
|
|
120901
|
+
external_id: string;
|
|
120902
|
+
/** @description The account’s display name at the provider. */
|
|
120903
|
+
name: string;
|
|
120904
|
+
} | null;
|
|
120905
|
+
/** @description Why the card is in this state: a failed first connect, `reconnect_required`, `sync_error` (connected, last sync failed), `access_revoked`, `disconnected_by_user`. */
|
|
120906
|
+
ProviderConnectionReason: {
|
|
120907
|
+
/**
|
|
120908
|
+
* @description A STABLE code — also the copy key. `user_cancelled`, `provider_denied`, `provider_error`, `token_exchange_failed`, `account_connected_elsewhere`, `no_candidates`, `connect_failed`, `internal_error`, `state_expired`, `state_invalid`, `handoff_expired`, `handoff_used`, `provider_not_configured`, `origin_not_allowed` come from the consent itself; `selection_expired`, `selection_conflict`, `reconnect_required`, `sync_error`, `access_revoked`, `disconnected_by_user`, `connection_not_found`, `handoff_not_found`, `unknown_error` are Vitrina’s own.
|
|
120909
|
+
* @enum {string}
|
|
120910
|
+
*/
|
|
120911
|
+
code: "user_cancelled" | "provider_denied" | "provider_error" | "token_exchange_failed" | "account_connected_elsewhere" | "no_candidates" | "connect_failed" | "internal_error" | "state_expired" | "state_invalid" | "handoff_expired" | "handoff_used" | "provider_not_configured" | "origin_not_allowed" | "selection_expired" | "selection_conflict" | "reconnect_required" | "sync_error" | "access_revoked" | "disconnected_by_user" | "connection_not_found" | "handoff_not_found" | "unknown_error";
|
|
120912
|
+
/** @description A ready Spanish sentence for the card, naming the provider. */
|
|
120913
|
+
label: string;
|
|
120914
|
+
/** @description Is trying the same thing again, right away, likely to work? */
|
|
120915
|
+
retryable: boolean;
|
|
120916
|
+
} | null;
|
|
120917
|
+
ProviderConnection: {
|
|
120918
|
+
/** @enum {string} */
|
|
120919
|
+
provider: "gohighlevel" | "mercadopago";
|
|
120920
|
+
display_name: string;
|
|
120921
|
+
/** @enum {string} */
|
|
120922
|
+
category: "crm" | "payments";
|
|
120923
|
+
/** @description One sentence: what connecting it does for the workspace. */
|
|
120924
|
+
description: string;
|
|
120925
|
+
/**
|
|
120926
|
+
* @description `not_connected` (never connected) → `connecting` (first consent in flight) → `connected` → `needs_reconnect` (the provider stopped honouring the grant; data is not updating) → `disconnected` (was connected, is not any more).
|
|
120927
|
+
* @enum {string}
|
|
120928
|
+
*/
|
|
120929
|
+
state: "not_connected" | "connecting" | "connected" | "needs_reconnect" | "disconnected";
|
|
120930
|
+
/** @description The state in Spanish, ready to render. */
|
|
120931
|
+
state_label: string;
|
|
120932
|
+
account: components["schemas"]["ProviderConnectionAccount"];
|
|
120933
|
+
last_account: components["schemas"]["ProviderConnectionAccount"] & unknown;
|
|
120934
|
+
reason: components["schemas"]["ProviderConnectionReason"];
|
|
120935
|
+
last_attempt: components["schemas"]["ProviderConnectionReason"] & unknown;
|
|
120936
|
+
/** @description The one thing the card should offer next. Never a dead end. */
|
|
120937
|
+
next_step: {
|
|
120938
|
+
/**
|
|
120939
|
+
* @description `connect` / `resume` / `reconnect` / `retry` → `POST …/connect`; `activate_addon` → the Vitrina Ads add-on; `choose_account` → `POST …/finalize`; `contact_support` and `none` call nothing. Disconnect is always available on a card that is not `not_connected`.
|
|
120940
|
+
* @enum {string}
|
|
120941
|
+
*/
|
|
120942
|
+
action: "connect" | "resume" | "choose_account" | "reconnect" | "retry" | "activate_addon" | "contact_support" | "none";
|
|
120943
|
+
/** @description The primary button’s label, or null for `none`. */
|
|
120944
|
+
label: string | null;
|
|
120945
|
+
};
|
|
120946
|
+
/** @description A connect in flight, if any — a consent the admin is on, or an account choice still owed. Rides on top of `state`: reconnecting a connected account does not make the card read `connecting`. */
|
|
120947
|
+
attempt: {
|
|
120948
|
+
/** @enum {string} */
|
|
120949
|
+
step: "consent" | "choose_account";
|
|
120950
|
+
/** @description The consent this attempt belongs to. On `choose_account`, send its `id` to `/finalize` as `handoff_id`. */
|
|
120951
|
+
handoff: {
|
|
120952
|
+
/** Format: uuid */
|
|
120953
|
+
id: string;
|
|
120954
|
+
expires_at: string;
|
|
120955
|
+
} | null;
|
|
120956
|
+
/** @description Step `choose_account` only: the accounts the consent can connect. Send one `external_id` to `/finalize`. */
|
|
120957
|
+
candidates: (components["schemas"]["ProviderConnectionAccount"] & Record<string, never>)[] | null;
|
|
120958
|
+
selection_expires_at: string | null;
|
|
120959
|
+
/** @description The picker / waiting title, in Spanish. */
|
|
120960
|
+
prompt: string;
|
|
120961
|
+
} | null;
|
|
120962
|
+
connected_at: string | null;
|
|
120963
|
+
disconnected_at: string | null;
|
|
120964
|
+
/** @description When the provider’s data last finished syncing. */
|
|
120965
|
+
last_synced_at: string | null;
|
|
120966
|
+
updated_at: string | null;
|
|
120967
|
+
/** @description Whether the Vitrina Ads add-on is active. `false` only on a card that outlived a lapsed add-on (a connection or a consent in flight): it stays visible and can be disconnected, and any step that would start a new consent becomes `activate_addon`. */
|
|
120968
|
+
addon_active: boolean;
|
|
120969
|
+
};
|
|
120970
|
+
ProviderConnectResult: {
|
|
120971
|
+
/** @description Send the WHOLE page here: it goes straight to the provider’s consent screen. Single-use, 45 minutes. */
|
|
120972
|
+
url: string;
|
|
120973
|
+
/** Format: uuid */
|
|
120974
|
+
handoff_id: string;
|
|
120975
|
+
expires_at: string;
|
|
120976
|
+
connection: components["schemas"]["ProviderConnection"];
|
|
120977
|
+
};
|
|
120978
|
+
ProviderConnectBody: {
|
|
120979
|
+
/** Format: uri */
|
|
120980
|
+
return_to: string;
|
|
120981
|
+
};
|
|
120982
|
+
ProviderReturnBody: {
|
|
120983
|
+
/** Format: uuid */
|
|
120984
|
+
handoff_id?: string;
|
|
120985
|
+
state?: string;
|
|
120986
|
+
/** @enum {string} */
|
|
120987
|
+
status?: "success" | "pending_selection" | "failed" | "cancelled";
|
|
120988
|
+
reason?: string;
|
|
120989
|
+
};
|
|
120990
|
+
ProviderFinalizeBody: {
|
|
120991
|
+
/** @description An `attempt.candidates[].external_id`, verbatim. */
|
|
120992
|
+
external_id: string;
|
|
120993
|
+
/**
|
|
120994
|
+
* Format: uuid
|
|
120995
|
+
* @description The `attempt.handoff.id` of the picker being answered. When sent and it is not the consent this card is waiting on, the answer is 409 `handoff_mismatch` — a stale tab cannot finalize a newer consent’s choice. Omitted: the current picker is finalized.
|
|
120996
|
+
*/
|
|
120997
|
+
handoff_id?: string;
|
|
120998
|
+
};
|
|
119174
120999
|
AdsOverviewDay: {
|
|
119175
121000
|
date: string;
|
|
119176
121001
|
/** @description `null` exactly when the engine could not scope spend. */
|
|
@@ -119240,6 +121065,33 @@ interface components {
|
|
|
119240
121065
|
/** @description `grain=day` only: every day of the previous window of equal length. */
|
|
119241
121066
|
previous_days?: components["schemas"]["AdsOverviewDay"][];
|
|
119242
121067
|
};
|
|
121068
|
+
/** @description Present on a conversational row: a message-only objective (`MESSAGES`), or conversations the platform reports, or conversations Vitrina counts. Also present with `data_complete: false` (figures `null`) when a read failed on a row that may be conversational (its objective unknown or in the messaging family) in a workspace with ad-opened conversations. ABSENT otherwise — never a row of zeros, never partial counts. */
|
|
121069
|
+
AdsConversational: {
|
|
121070
|
+
/** @description `false` when a read behind the line failed or timed out: the `null` figures are unknown, not zero («sin datos de Meta por ahora»). `true` = every figure was read. */
|
|
121071
|
+
data_complete: boolean;
|
|
121072
|
+
/** @description The campaign objective as the ad platform names it (`OUTCOME_ENGAGEMENT`, `MESSAGES`, …); `null` when unknown. */
|
|
121073
|
+
objective: string | null;
|
|
121074
|
+
/** @description The ad platform’s own count («conversaciones iniciadas», its 7-day window, every sender) — a DIFFERENT population from `vitrina`; never add or compare the two. `null` when it reports none. */
|
|
121075
|
+
started: {
|
|
121076
|
+
/** @description Conversations started, as the ad platform reports them. */
|
|
121077
|
+
conversations: number;
|
|
121078
|
+
/** @description The row’s `spend` ÷ conversations started, whole CLP — the same spend basis as `vitrina.cost_per_conversation`; `null` when unknown. */
|
|
121079
|
+
cost_per_conversation: number | null;
|
|
121080
|
+
} | null;
|
|
121081
|
+
/** @description Vitrina’s own conversations from the ad — deterministic counts, never a credited share. `null` when Vitrina counts none in the period (or the ad → campaign map could not be read now). */
|
|
121082
|
+
vitrina: {
|
|
121083
|
+
/** @description Conversations whose first message came from this ad (or an ad of this campaign), opened in the period (America/Santiago days) — Vitrina’s own count. */
|
|
121084
|
+
conversations: number;
|
|
121085
|
+
/** @description «Respondidas»: of those, answered at least once by the team, the AI agent or an integration. */
|
|
121086
|
+
replied: number;
|
|
121087
|
+
/** @description Of those, with a booked appointment (cita / visita) recorded against them, whenever it was booked. */
|
|
121088
|
+
appointments: number;
|
|
121089
|
+
/** @description Of those, closed (a sale / an accepted plan) recorded against them, whenever it closed. */
|
|
121090
|
+
closed: number;
|
|
121091
|
+
/** @description The row’s `spend` ÷ `conversations`, whole CLP — the same spend basis as `started.cost_per_conversation`. */
|
|
121092
|
+
cost_per_conversation: number | null;
|
|
121093
|
+
} | null;
|
|
121094
|
+
};
|
|
119243
121095
|
AdsCampaigns: {
|
|
119244
121096
|
data: {
|
|
119245
121097
|
campaign_id: string;
|
|
@@ -119268,6 +121120,7 @@ interface components {
|
|
|
119268
121120
|
/** @description Conversions credited primarily to the campaign that day (each conversion counted once, on its largest-credit campaign). `null` when unknown: credit not available yet, the campaign outside the credited set read (top 25 by outcomes), or a day before the credit window (the last 92 days). Under a multi-touch model the days can sum to less than the row’s `outcome_count`. */
|
|
119269
121121
|
outcome_count: number | null;
|
|
119270
121122
|
}[] | null;
|
|
121123
|
+
conversational?: components["schemas"]["AdsConversational"];
|
|
119271
121124
|
}[];
|
|
119272
121125
|
};
|
|
119273
121126
|
AdsAttributedSales: {
|
|
@@ -119332,6 +121185,7 @@ interface components {
|
|
|
119332
121185
|
/** @description Percent (clicks ÷ impressions × 100), like the row’s `ctr`; `null` on a day without impressions. */
|
|
119333
121186
|
ctr: number | null;
|
|
119334
121187
|
}[] | null;
|
|
121188
|
+
conversational?: components["schemas"]["AdsConversational"] & unknown;
|
|
119335
121189
|
}[];
|
|
119336
121190
|
};
|
|
119337
121191
|
AdsHealth: {
|
|
@@ -119349,6 +121203,18 @@ interface components {
|
|
|
119349
121203
|
tracking_healthy: boolean;
|
|
119350
121204
|
coverage_interpretation: string;
|
|
119351
121205
|
missing: string[];
|
|
121206
|
+
/** @description The website tag signal behind `missing[tracker]`. `null` when the engine did not report it (unknown, never «silent»). */
|
|
121207
|
+
tracker: {
|
|
121208
|
+
/**
|
|
121209
|
+
* @description `live` = 10 or more web-tag touches in the window and one in the last 7 days; `sparse` = at least one touch but not live (few visits, or none in the last 7 days); `missing` = no touch at all. `missing[]` lists `tracker` for both `sparse` and `missing` — only `missing` means the tag sent nothing.
|
|
121210
|
+
* @enum {string}
|
|
121211
|
+
*/
|
|
121212
|
+
status: "live" | "sparse" | "missing";
|
|
121213
|
+
web_touches: number;
|
|
121214
|
+
last_web_touch: string | null;
|
|
121215
|
+
/** @description A web-tag touch inside the last 7 days. */
|
|
121216
|
+
fresh: boolean;
|
|
121217
|
+
} | null;
|
|
119352
121218
|
};
|
|
119353
121219
|
traceable_roas_trend: {
|
|
119354
121220
|
recent_roas: number | null;
|
|
@@ -119530,7 +121396,7 @@ interface components {
|
|
|
119530
121396
|
/** @description `<kind>:<target external id>:<YYYY-MM-DD>` — a composite key, stable for a day. */
|
|
119531
121397
|
key: string;
|
|
119532
121398
|
/** @enum {string} */
|
|
119533
|
-
kind: "pause_ad" | "budget_change" | "adset_duplicate_swap" | "utm_refresh" | "wiring_recheck" | "url_tags_fix" | "send_setup" | "send_stage" | "send_dataset" | "send_stop" | "send_protected_move" | "nav";
|
|
121399
|
+
kind: "pause_ad" | "campaign_pause" | "budget_change" | "adset_duplicate_swap" | "utm_refresh" | "wiring_recheck" | "url_tags_fix" | "send_setup" | "send_stage" | "send_dataset" | "send_stop" | "send_protected_move" | "nav";
|
|
119534
121400
|
screen: ("resumen" | "campanas" | "creativos" | "salud" | "envio")[];
|
|
119535
121401
|
/** @description The one card the rail leads with. */
|
|
119536
121402
|
primary: boolean;
|
|
@@ -119552,7 +121418,7 @@ interface components {
|
|
|
119552
121418
|
external_id: string;
|
|
119553
121419
|
name: string | null;
|
|
119554
121420
|
} | null;
|
|
119555
|
-
/** @description `url_tags_fix` (and its read-only `nav` fallback)
|
|
121421
|
+
/** @description `url_tags_fix` (and its read-only `nav` fallback): the ads whose «Parámetros de URL» do not carry the ad id where attribution reads it, busiest first, at most what one fix accepts (25). Ad set and campaign are named, not identified (the audit carries names only). `campaign_pause`: the campaign’s delivering ads, busiest first (at most 6 — the card’s thumbnails; the live count is the preview’s). */
|
|
119556
121422
|
ads?: {
|
|
119557
121423
|
/** @description The ad’s Meta id. */
|
|
119558
121424
|
external_id: string;
|
|
@@ -119561,7 +121427,7 @@ interface components {
|
|
|
119561
121427
|
campaign_name: string | null;
|
|
119562
121428
|
}[];
|
|
119563
121429
|
};
|
|
119564
|
-
/** @description The engine’s own vocabulary, e.g. `{ budget_change_pct: 20 }`. `url_tags_fix`: `{ ads: [{ external_id, expected_url_tags, url_tags }] }` — each ad’s current parameters (null = none) and exactly what it gets. «Enviar a Meta»: `send_setup`/`send_dataset` `{ dataset_id }`, `send_stage` `{ stage, enabled, meta_event, active_ad_sets }`. */
|
|
121430
|
+
/** @description The engine’s own vocabulary, e.g. `{ budget_change_pct: 20 }`. `url_tags_fix`: `{ ads: [{ external_id, expected_url_tags, url_tags }] }` — each ad’s current parameters (null = none) and exactly what it gets. «Enviar a Meta»: `send_setup`/`send_dataset` `{ dataset_id }`, `send_stage` `{ stage, enabled, meta_event, active_ad_sets }`. `campaign_pause`: `{ period_spend, period_days, delivering_ads_count, avg_daily_spend_7d }` — the campaign’s spend in the listed period (the account currency’s major units), the period’s days and its delivering ads, what the card draws at rest (spend → 0, ~spend/days a day); `avg_daily_spend_7d` is the live 7-day daily mean the preview shows (`AdsMoney`: exact decimal + currency), `null` when the list could not know it (real mode reads it only at preview) — fall back to `period_spend / period_days`, labelled as the period. */
|
|
119565
121431
|
params: {
|
|
119566
121432
|
[key: string]: unknown;
|
|
119567
121433
|
};
|
|
@@ -119571,7 +121437,7 @@ interface components {
|
|
|
119571
121437
|
/** @description Which operation executes it; `null` for `nav`. */
|
|
119572
121438
|
engine_ref: {
|
|
119573
121439
|
/** @enum {string} */
|
|
119574
|
-
op: "recommendations.apply" | "ads.pause" | "wiring.ad_sets" | "quality.utm_refresh" | "wiring.recheck" | "actions.rollback" | "quality.url_tags_apply" | "quality.url_tags_undo" | "send.setup" | "send.dataset" | "send.stage" | "send.stop" | "send.restore";
|
|
121440
|
+
op: "recommendations.apply" | "ads.pause" | "campaigns.pause" | "campaigns.resume" | "wiring.ad_sets" | "quality.utm_refresh" | "wiring.recheck" | "actions.rollback" | "quality.url_tags_apply" | "quality.url_tags_undo" | "send.setup" | "send.dataset" | "send.stage" | "send.stop" | "send.restore";
|
|
119575
121441
|
recommendation_id?: string;
|
|
119576
121442
|
} | null;
|
|
119577
121443
|
/** @description `nav` only: a workspace-relative path (`/anuncios/atribuidos?c=…`, `/anuncios/activar?paso=tag`), or an absolute Meta Ads Manager URL built from Meta ids (`https://www.facebook.com/adsmanager/…`) — open it in a new tab; it changes nothing by itself. */
|
|
@@ -119586,6 +121452,43 @@ interface components {
|
|
|
119586
121452
|
*/
|
|
119587
121453
|
disabled_reason?: "consent_pending";
|
|
119588
121454
|
};
|
|
121455
|
+
/** @description Mean daily spend over the last `spend_window_days` complete days — the «~$X al día» the pause stops. `null` = nothing spent / unknown. */
|
|
121456
|
+
AdsMoney: {
|
|
121457
|
+
/** @description Exact decimal string in the currency’s MAJOR units (never a float): `"12345.5"`. Parse before arithmetic. */
|
|
121458
|
+
amount: string;
|
|
121459
|
+
/** @description ISO 4217, e.g. `CLP`. */
|
|
121460
|
+
currency: string | null;
|
|
121461
|
+
/** @description Formatted for display (`$12.346`); `null` when the currency is unknown. */
|
|
121462
|
+
display: string | null;
|
|
121463
|
+
} | null;
|
|
121464
|
+
/** @description `campaign_pause` only: the live campaign, from ONE status read — everything the sheet and the card’s delta draw, no second call. */
|
|
121465
|
+
AdsCampaignPauseSnapshot: {
|
|
121466
|
+
/** @description The campaign’s Meta id. */
|
|
121467
|
+
external_id: string;
|
|
121468
|
+
name: string | null;
|
|
121469
|
+
/** @description Configured status: ACTIVE | PAUSED | ARCHIVED | DELETED. */
|
|
121470
|
+
status: string | null;
|
|
121471
|
+
/** @description Meta’s delivery verdict (ACTIVE, IN_PROCESS, WITH_ISSUES, …). */
|
|
121472
|
+
effective_status: string | null;
|
|
121473
|
+
/**
|
|
121474
|
+
* @description `live` — read from Meta just now. A preview answers only on a live read: when Meta cannot be read it is 503 `ADS_ACTION_READ_UNAVAILABLE` (retry in a moment).
|
|
121475
|
+
* @enum {string}
|
|
121476
|
+
*/
|
|
121477
|
+
status_source: "live" | "synced";
|
|
121478
|
+
/** @description Ads the pause stops right now — «detiene {n} anuncios». `null` = unknown. */
|
|
121479
|
+
delivering_ads_count: number | null;
|
|
121480
|
+
avg_daily_spend: components["schemas"]["AdsMoney"];
|
|
121481
|
+
spend_window_days: number | null;
|
|
121482
|
+
/**
|
|
121483
|
+
* @description `campaign` — one campaign budget; `ad_set` — each ad set has its own.
|
|
121484
|
+
* @enum {string|null}
|
|
121485
|
+
*/
|
|
121486
|
+
budget_level: "campaign" | "ad_set" | null;
|
|
121487
|
+
daily_budget: components["schemas"]["AdsMoney"] & unknown;
|
|
121488
|
+
lifetime_budget: components["schemas"]["AdsMoney"] & unknown;
|
|
121489
|
+
/** @description When the status was read (ISO). */
|
|
121490
|
+
as_of: string | null;
|
|
121491
|
+
};
|
|
119589
121492
|
AdsActionPreview: {
|
|
119590
121493
|
/** Format: uuid */
|
|
119591
121494
|
preview_id: string;
|
|
@@ -119596,11 +121499,18 @@ interface components {
|
|
|
119596
121499
|
label: string;
|
|
119597
121500
|
before: string;
|
|
119598
121501
|
after: string;
|
|
121502
|
+
/**
|
|
121503
|
+
* @description `kept`: a fact the action does not change — render ONE value (`before`; `after` repeats it) with `note`. Absent: a before → after change.
|
|
121504
|
+
* @enum {string}
|
|
121505
|
+
*/
|
|
121506
|
+
kind?: "kept";
|
|
121507
|
+
/** @description `kept` rows: why it stays («Se conserva …»). */
|
|
121508
|
+
note?: string;
|
|
119599
121509
|
}[];
|
|
119600
121510
|
warnings: string[];
|
|
119601
121511
|
/** @description The consent-bearing previews only (duplicate-and-swap, `url_tags_fix`, «Enviar a Meta» when it asks): `consent_terms.text` split into lines, for display (verbatim). */
|
|
119602
121512
|
consent: string[];
|
|
119603
|
-
/** @description The consent-bearing previews only: what the owner accepts before confirming. Execute must send `consent: { version, text_hash }`. For `url_tags_fix` the text is one sentence: rewriting an ad’s parameters replaces its creative, which can restart the learning phase of the affected ad sets. «Enviar a Meta»: `send_setup` always carries the owner’s authorisation of the send; `send_dataset`, and a `send_stage` off or `send_stop` that stops an event active ad sets optimise on, carry the learning-reset line. */
|
|
121513
|
+
/** @description The consent-bearing previews only: what the owner accepts before confirming. Execute must send `consent: { version, text_hash }`. For `campaign_pause`: every ad stops at once; «Reanudar» brings it back with the same budget, ads paused on their own stay paused, and a pause of 7 days or more can restart Meta’s learning phase. For `url_tags_fix` the text is one sentence: rewriting an ad’s parameters replaces its creative, which can restart the learning phase of the affected ad sets. «Enviar a Meta»: `send_setup` always carries the owner’s authorisation of the send; `send_dataset`, and a `send_stage` off or `send_stop` that stops an event active ad sets optimise on, carry the learning-reset line. */
|
|
119604
121514
|
consent_terms: {
|
|
119605
121515
|
version: string;
|
|
119606
121516
|
/** @enum {string} */
|
|
@@ -119612,14 +121522,17 @@ interface components {
|
|
|
119612
121522
|
} | null;
|
|
119613
121523
|
reversible: boolean;
|
|
119614
121524
|
/** @enum {string|null} */
|
|
119615
|
-
engine_op: "recommendations.apply" | "ads.pause" | "wiring.ad_sets" | "quality.utm_refresh" | "wiring.recheck" | "actions.rollback" | "quality.url_tags_apply" | "quality.url_tags_undo" | "send.setup" | "send.dataset" | "send.stage" | "send.stop" | "send.restore" | null;
|
|
121525
|
+
engine_op: "recommendations.apply" | "ads.pause" | "campaigns.pause" | "campaigns.resume" | "wiring.ad_sets" | "quality.utm_refresh" | "wiring.recheck" | "actions.rollback" | "quality.url_tags_apply" | "quality.url_tags_undo" | "send.setup" | "send.dataset" | "send.stage" | "send.stop" | "send.restore" | null;
|
|
121526
|
+
/** @description `campaign_pause` only: the line the sheet leads with — «Pausar «{campaign}» · detiene {n} anuncios · ~$X al día» (the count and the daily figure are dropped when unknown). */
|
|
121527
|
+
summary?: string;
|
|
121528
|
+
campaign?: components["schemas"]["AdsCampaignPauseSnapshot"];
|
|
119616
121529
|
};
|
|
119617
121530
|
AdsActionExecution: {
|
|
119618
121531
|
/** Format: uuid */
|
|
119619
121532
|
id: string;
|
|
119620
121533
|
action_key: string;
|
|
119621
121534
|
/** @enum {string} */
|
|
119622
|
-
kind: "pause_ad" | "budget_change" | "adset_duplicate_swap" | "utm_refresh" | "wiring_recheck" | "url_tags_fix" | "send_setup" | "send_stage" | "send_dataset" | "send_stop";
|
|
121535
|
+
kind: "pause_ad" | "campaign_pause" | "budget_change" | "adset_duplicate_swap" | "utm_refresh" | "wiring_recheck" | "url_tags_fix" | "send_setup" | "send_stage" | "send_dataset" | "send_stop";
|
|
119623
121536
|
/** @enum {string} */
|
|
119624
121537
|
status: "queued" | "running" | "succeeded" | "failed" | "refused" | "rolled_back";
|
|
119625
121538
|
target: {
|
|
@@ -119637,7 +121550,7 @@ interface components {
|
|
|
119637
121550
|
name: string | null;
|
|
119638
121551
|
}[];
|
|
119639
121552
|
};
|
|
119640
|
-
/** @description What happened. `url_tags_fix` adds `partial` (true when fewer ads were corrected than asked — never show «Hecho» then), `corrected_count`, `requested_count` and `ads[]`: per ad `{external_id, name, result: corrected|skipped|failed, code, message, url_tags_after, engine_action_id, undo_available}` (an ad that already carried the parameters counts as corrected; it is undoable when this fix wrote it). Its undo (a rollback row) reports `undone_count`, `drifted_count` (changed in Meta since — never touched), `gone_count` (already undone elsewhere — no longer undoable from here), `reconnect_count` (Meta asks to reconnect), `retryable_count` (no answer or reconnect — the original stays undoable and the next rollback sends only those ads), `requested_count`, `partial` and `ads[]` `{external_id, name, result: undone|drifted|gone|retryable|reconnect, code, message}`; a failed or refused fix still carries `ads[]`. */
|
|
121553
|
+
/** @description What happened. `url_tags_fix` adds `partial` (true when fewer ads were corrected than asked — never show «Hecho» then), `corrected_count`, `requested_count` and `ads[]`: per ad `{external_id, name, result: corrected|skipped|failed, code, message, url_tags_after, engine_action_id, undo_available}` (an ad that already carried the parameters counts as corrected; it is undoable when this fix wrote it). Its undo (a rollback row) reports `undone_count`, `drifted_count` (changed in Meta since — never touched), `gone_count` (already undone elsewhere — no longer undoable from here), `reconnect_count` (Meta asks to reconnect), `retryable_count` (no answer or reconnect — the original stays undoable and the next rollback sends only those ads), `requested_count`, `partial` and `ads[]` `{external_id, name, result: undone|drifted|gone|retryable|reconnect, code, message}`; a failed or refused fix still carries `ads[]`. `campaign_pause` (and its «Reanudar», a rollback row) adds `engine_outcome` (`applied` | `no_change` — already in that state, nothing written | `replayed`), `status`, `previous_status`, `campaign_name`, `affected_ads_count` (ads stopped, or freed by the resume; `null` when Meta gave no count) and `journal_line` («pausaste la campaña «X» · 4 anuncios» / «reanudaste …»; `null` on `no_change`). A «Reanudar» never brings back ads that were paused on their own. */
|
|
119641
121554
|
outcome: {
|
|
119642
121555
|
summary: string;
|
|
119643
121556
|
engine_action_id: string | null;
|
|
@@ -119694,6 +121607,35 @@ interface components {
|
|
|
119694
121607
|
*/
|
|
119695
121608
|
collector: "same_origin" | "cname" | "none" | null;
|
|
119696
121609
|
};
|
|
121610
|
+
/** @description The ad that opened the originating conversation — Vitrina’s own fact from the first message (a click-to-WhatsApp or Instagram / Messenger ad referral), known at once. Not a credit claim: `ad` is the credit. `null` when no ad opened the thread (or it was a boosted post). */
|
|
121611
|
+
AdsFeedOrigin: {
|
|
121612
|
+
/**
|
|
121613
|
+
* @description Where the person wrote from the ad.
|
|
121614
|
+
* @enum {string}
|
|
121615
|
+
*/
|
|
121616
|
+
platform: "whatsapp" | "instagram" | "messenger";
|
|
121617
|
+
/** @description The AD’s platform id (never a post id). */
|
|
121618
|
+
external_id: string;
|
|
121619
|
+
/** @description What to render: the ad’s name in the ad account, else its headline, else `null` («Mensaje por un anuncio de Instagram»). */
|
|
121620
|
+
name: string | null;
|
|
121621
|
+
/** @description The ad’s name in the ad account; `null` when unknown. */
|
|
121622
|
+
ad_name: string | null;
|
|
121623
|
+
/** @description The ad’s headline — the advertiser’s copy, never the customer’s words. */
|
|
121624
|
+
headline: string | null;
|
|
121625
|
+
/** @description The ad’s campaign, when the ads read knows it. */
|
|
121626
|
+
campaign: {
|
|
121627
|
+
/** @description The campaign’s platform id, when known. */
|
|
121628
|
+
external_id: string | null;
|
|
121629
|
+
name: string | null;
|
|
121630
|
+
} | null;
|
|
121631
|
+
/** @description Still image of the creative: Vitrina’s durable copy when `media_archived`, else the platform’s own link, which expires (render with a fallback). */
|
|
121632
|
+
thumbnail_url: string | null;
|
|
121633
|
+
media_archived: boolean;
|
|
121634
|
+
/** @description When the person first wrote from the ad (ISO 8601). */
|
|
121635
|
+
first_message_at: string | null;
|
|
121636
|
+
/** @description `true` when the credited campaign (`ad.campaign`) is this ad’s campaign, `false` when the credit went to another campaign, `null` when unknown or not credited yet. */
|
|
121637
|
+
matches_credit: boolean | null;
|
|
121638
|
+
} | null;
|
|
119697
121639
|
AdsFeedItem: {
|
|
119698
121640
|
/** Format: uuid */
|
|
119699
121641
|
id: string;
|
|
@@ -119706,7 +121648,7 @@ interface components {
|
|
|
119706
121648
|
occurred_at: string;
|
|
119707
121649
|
/** @description When Vitrina recorded it — the cursor field, microsecond-exact. */
|
|
119708
121650
|
created_at: string;
|
|
119709
|
-
/** @description The engine accepted the outcome as a conversion it can attribute.
|
|
121651
|
+
/** @description The engine accepted the outcome as a conversion it can attribute. Whether the credit can still arrive is `attribution`. */
|
|
119710
121652
|
matched: boolean;
|
|
119711
121653
|
/** @description CLP for money stages; `null` otherwise (never 0). */
|
|
119712
121654
|
value: number | null;
|
|
@@ -119733,6 +121675,24 @@ interface components {
|
|
|
119733
121675
|
} | null;
|
|
119734
121676
|
credited_weight: number | null;
|
|
119735
121677
|
touch_count: number | null;
|
|
121678
|
+
/** @description Set when the contact was matched to the patient AUTOMATICALLY (an identifier held by exactly one patient and one contact) — show «Vinculado automáticamente» with the method. `null`/absent = a family bond, a booking link or the contact itself. Undo with `POST /clinic/auto-links/{id}/reject`. */
|
|
121679
|
+
identity?: {
|
|
121680
|
+
/** @enum {string} */
|
|
121681
|
+
source: "auto_link";
|
|
121682
|
+
/** @enum {string} */
|
|
121683
|
+
method: "phone_unique" | "email_unique";
|
|
121684
|
+
} | null;
|
|
121685
|
+
origin: components["schemas"]["AdsFeedOrigin"];
|
|
121686
|
+
/**
|
|
121687
|
+
* @description Which source the row names its ad from: `engine` — `ad` (the credited campaign) is set; `conversation` — `ad` is `null` and `origin` is set: show the origin, never «anuncio por confirmar» (whether the credit may still come is `attribution`); `null` — neither is known.
|
|
121688
|
+
* @enum {string|null}
|
|
121689
|
+
*/
|
|
121690
|
+
origin_source: "engine" | "conversation" | null;
|
|
121691
|
+
/**
|
|
121692
|
+
* @description Whether the credit (`ad`) can still arrive: `credited` — `ad` is set; `pending` — not yet («atribución por confirmar» beside `origin`, else «anuncio por confirmar»); `final` — it never will: the contact was removed from attribution, the outcome is not one an ad can be credited with, or 72 hours after the outcome’s time a complete credit read still names no campaign. Show `origin` alone, or «sin anuncio» — never «por confirmar». A row is never settled while the credit read is incomplete (`meta.enrichment` not `ready`).
|
|
121693
|
+
* @enum {string}
|
|
121694
|
+
*/
|
|
121695
|
+
attribution: "credited" | "pending" | "final";
|
|
119736
121696
|
};
|
|
119737
121697
|
AdsJourneyStepAd: {
|
|
119738
121698
|
/** @description The ad’s PLATFORM id; `null` when only the campaign is known. */
|
|
@@ -119751,7 +121711,7 @@ interface components {
|
|
|
119751
121711
|
/** @description Stable key for the step. For a step recorded by Vitrina it is the feed item id (`GET /ads/feed` `data[].id`). */
|
|
119752
121712
|
id: string;
|
|
119753
121713
|
/**
|
|
119754
|
-
* @description Touches: `ad` (an off-site ad touch — an ad click or a click-to-WhatsApp referral), `click` (a visit that landed from an ad click, or a tracked link click), `visit` (a site visit), `chat` (the first message, or a social interaction). Recorded steps, in funnel order: `chat` (first message), `booking`, `attended`, `quote`, `accepted` (a presupuesto accepted / a sale closed), `payment`; `outcome` for anything else.
|
|
121714
|
+
* @description Touches: `ad` (an off-site ad touch — an ad click or a click-to-WhatsApp referral), `click` (a visit that landed from an ad click, or a tracked link click), `visit` (a site visit), `chat` (the first message, or a social interaction). «Mensaje por el anuncio X»: a `chat` step with `origin: vitrina`, `stage: null`, `id` = the conversation’s id and the ad on `ad`, at the moment the person first wrote from the ad — one per ad-opened conversation; the same ad is never also on the first-message fact, and the engine’s touch of that same referral (the ad’s, or a click-id-only one) is folded into it, credit mark included. Recorded steps, in funnel order: `chat` (first message), `booking`, `attended`, `quote`, `accepted` (a presupuesto accepted / a sale closed), `payment`; `outcome` for anything else.
|
|
119755
121715
|
* @enum {string}
|
|
119756
121716
|
*/
|
|
119757
121717
|
kind: "ad" | "click" | "visit" | "chat" | "outcome" | "booking" | "attended" | "quote" | "accepted" | "payment";
|
|
@@ -119775,7 +121735,7 @@ interface components {
|
|
|
119775
121735
|
/** @description The touch the outcome was credited to, under `model`. */
|
|
119776
121736
|
credited: boolean;
|
|
119777
121737
|
/**
|
|
119778
|
-
* @description How the touch is tied to this person, when proven: `ctwa_referral` (the click-to-WhatsApp / Instagram ad referral), `click_id` (the ad click id the outcome carried), `link_token` (a link Vitrina sent), `anonymous_id` (the same browser). `null` on recorded steps.
|
|
121738
|
+
* @description How the touch is tied to this person, when proven: `ctwa_referral` (the click-to-WhatsApp / Instagram ad referral), `click_id` (the ad click id the outcome carried), `link_token` (a link Vitrina sent), `anonymous_id` (the same browser). `null` on recorded steps; `ctwa_referral` on the «Mensaje por el anuncio» step.
|
|
119779
121739
|
* @enum {string|null}
|
|
119780
121740
|
*/
|
|
119781
121741
|
join_method: "ctwa_referral" | "click_id" | "link_token" | "anonymous_id" | null;
|
|
@@ -119883,7 +121843,7 @@ declare function createClient(opts: CreateClientOptions): VitrinaClient;
|
|
|
119883
121843
|
* is regenerated — narrow on the ones you handle, never assume this
|
|
119884
121844
|
* list is exhaustive at runtime.
|
|
119885
121845
|
*/
|
|
119886
|
-
type ErrorCode = 'VALIDATION_ERROR' | 'NOT_FOUND' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'CONFLICT' | 'UNIQUE_CONFLICT' | 'IDEMPOTENCY_KEY_CONFLICT' | 'VERTICAL_NOT_ENABLED' | 'ENTITLEMENT_NOT_ACTIVE' | 'UNSUPPORTED_VEHICLE_TYPE' | 'NO_OFFERING_ADAPTER' | 'PAYLOAD_TOO_LARGE' | 'UNSUPPORTED_MEDIA_TYPE' | 'UPSTREAM_ERROR' | 'RATE_LIMITED' | 'GONE' | 'INTERNAL_ERROR' | 'MESSAGING_ACCOUNT_TENANT_MISSING' | 'COPILOT_APPROVALS_UNAVAILABLE' | 'COPILOT_APPROVAL_REPLAY_BLOCKED' | 'COPILOT_DISABLED' | 'COPILOT_BUDGET_EXCEEDED' | 'DEALER_SITES_NOT_CONFIGURED' | 'STOREFRONT_ZONES_NOT_CONFIGURED' | 'RECONTACTO_NOT_ENABLED' | 'SYNC_QUEUE_UNAVAILABLE' | 'SHARE_IMAGE_UNAVAILABLE' | 'ATTRIBUTION_PROFILE_UNAVAILABLE' | 'DOCUMENT_LOGO_UNAVAILABLE' | 'ATTRIBUTION_PROFILE_MISMATCH' | 'ADS_KEY_NEEDS_REMINT' | 'ADS_ACTION_REPLAY_BLOCKED' | 'ADS_ACTION_NOT_AVAILABLE' | 'ADS_ACTION_NOT_REVERSIBLE' | 'ADS_ACTION_CONSENT_REQUIRED' | 'MISSING_SIGNATURE' | 'MALFORMED_SIGNATURE' | 'STALE_SIGNATURE' | 'INVALID_SIGNATURE' | 'REPLAY_DETECTED' | 'TURNSTILE_UNAVAILABLE' | 'TASADOR_QUOTA_EXHAUSTED' | 'TASADOR_ANON_DAILY_LIMIT' | 'TASADOR_CAPACITY_REACHED' | 'CLINIC_PLAN_REQUIRED' | 'TENANT_BILLING_PAUSED' | 'FACEBOOK_MARKETPLACE_NOT_AVAILABLE' | 'WORKSPACE_MEMBER_INACTIVE' | 'DEVICE_AGENT_ALREADY_PAIRED' | 'DEVICE_AGENT_SELF_REQUIRES_USER' | 'DEVICE_AGENT_KIND_NOT_ALLOWED' | 'DEVICE_TASK_STATUS_NOT_ALLOWED' | 'FACEBOOK_MARKETPLACE_NO_PHONE_AGENT' | 'FACEBOOK_MARKETPLACE_THREAD_NOT_ADDRESSABLE' | 'FACEBOOK_MARKETPLACE_ATTACHMENT_UNSUPPORTED' | 'REPLY_PACING_LOCKED' | 'SANDBOX_CHANNEL_FORBIDDEN' | 'SANDBOX_BILLING_FORBIDDEN' | 'SANDBOX_NOT_PROVISIONED' | 'SANDBOX_RESET_UNAVAILABLE' | 'CONNECTED_APP_SENSITIVE_DATA' | 'handoff_mismatch' | 'sync_in_flight' | '
|
|
121846
|
+
type ErrorCode = 'VALIDATION_ERROR' | 'NOT_FOUND' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'CONFLICT' | 'UNIQUE_CONFLICT' | 'IDEMPOTENCY_KEY_CONFLICT' | 'VERTICAL_NOT_ENABLED' | 'ENTITLEMENT_NOT_ACTIVE' | 'UNSUPPORTED_VEHICLE_TYPE' | 'NO_OFFERING_ADAPTER' | 'PAYLOAD_TOO_LARGE' | 'UNSUPPORTED_MEDIA_TYPE' | 'UPSTREAM_ERROR' | 'RATE_LIMITED' | 'GONE' | 'INTERNAL_ERROR' | 'MESSAGING_ACCOUNT_TENANT_MISSING' | 'COPILOT_APPROVALS_UNAVAILABLE' | 'COPILOT_APPROVAL_REPLAY_BLOCKED' | 'COPILOT_DISABLED' | 'COPILOT_BUDGET_EXCEEDED' | 'DEALER_SITES_NOT_CONFIGURED' | 'STOREFRONT_ZONES_NOT_CONFIGURED' | 'RECONTACTO_NOT_ENABLED' | 'SYNC_QUEUE_UNAVAILABLE' | 'SHARE_IMAGE_UNAVAILABLE' | 'ATTRIBUTION_PROFILE_UNAVAILABLE' | 'DOCUMENT_LOGO_UNAVAILABLE' | 'ATTRIBUTION_PROFILE_MISMATCH' | 'ADS_KEY_NEEDS_REMINT' | 'ADS_ACTION_READ_UNAVAILABLE' | 'ADS_ACTION_REPLAY_BLOCKED' | 'ADS_ACTION_NOT_AVAILABLE' | 'ADS_ACTION_NOT_REVERSIBLE' | 'ADS_ACTION_CONSENT_REQUIRED' | 'MISSING_SIGNATURE' | 'MALFORMED_SIGNATURE' | 'STALE_SIGNATURE' | 'INVALID_SIGNATURE' | 'REPLAY_DETECTED' | 'TURNSTILE_UNAVAILABLE' | 'TASADOR_QUOTA_EXHAUSTED' | 'TASADOR_ANON_DAILY_LIMIT' | 'TASADOR_CAPACITY_REACHED' | 'CLINIC_PLAN_REQUIRED' | 'TENANT_BILLING_PAUSED' | 'FACEBOOK_MARKETPLACE_NOT_AVAILABLE' | 'WORKSPACE_MEMBER_INACTIVE' | 'DEVICE_AGENT_ALREADY_PAIRED' | 'DEVICE_AGENT_SELF_REQUIRES_USER' | 'DEVICE_AGENT_KIND_NOT_ALLOWED' | 'DEVICE_TASK_STATUS_NOT_ALLOWED' | 'FACEBOOK_MARKETPLACE_NO_PHONE_AGENT' | 'FACEBOOK_MARKETPLACE_THREAD_NOT_ADDRESSABLE' | 'FACEBOOK_MARKETPLACE_ATTACHMENT_UNSUPPORTED' | 'REPLY_PACING_LOCKED' | 'SANDBOX_CHANNEL_FORBIDDEN' | 'SANDBOX_BILLING_FORBIDDEN' | 'SANDBOX_NOT_PROVISIONED' | 'SANDBOX_RESET_UNAVAILABLE' | 'CONNECTED_APP_SENSITIVE_DATA' | 'handoff_mismatch' | 'sync_in_flight' | 'disconnect_refused' | 'start_again' | 'reconnect' | 'not_selecting' | 'selection_expired' | 'selection_conflict' | 'account_connected_elsewhere' | 'candidate_unavailable' | 'integration_managed' | 'partner_token_invalid' | 'OUTBOUND_BLOCKED' | 'OUTBOUND_WARNING' | 'dpa_acceptance_required' | 'EMAIL_SENDER_UNRESOLVED' | 'CAMPAIGN_FROM_CONNECTED_MAILBOX' | 'BANK_FEED_NOT_CONFIGURED' | 'ADDON_NOT_PRICED' | 'MIRROR_LINES_UNMAPPED';
|
|
119887
121847
|
declare const ERROR_CODES: readonly ErrorCode[];
|
|
119888
121848
|
|
|
119889
121849
|
/**
|