@whop/elements 0.0.0 → 1.0.0-beta.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/ads.d.cts ADDED
@@ -0,0 +1,585 @@
1
+ /**
2
+ * Options for `whop.ads.create()`: the controller's props plus its `on<Event>` callbacks. In React, these are the `<Ads>` component's props.
3
+ * @example
4
+ * ```ts
5
+ * import { loadWhop } from "@whop/elements";
6
+ *
7
+ * const whop = (await loadWhop())({ locale: "en" });
8
+ * const ads = whop.ads.create({}); // options: props + on<Event> callbacks
9
+ * ```
10
+ * @see https://docs.whop.com/elements/latest/ads/overview
11
+ */
12
+ export interface AdsOptions {
13
+ /**
14
+ * Whop account ID, prefixed `biz_`, whose advertising this reads. Required; this is not an ad account ID.
15
+ * @default ""
16
+ */
17
+ accountId?: string;
18
+ /**
19
+ * A scoped token every surface under this handle reads and writes with. **Mint one token for the whole handle, not one per element.** Work out the scopes of every element you are going to mount, request them on a single token, and set it here — the handle projects that one credential into each element's frame, so a second token per surface buys nothing and leaves you several expiration dates to track instead of one. Mint it on your server with `POST /api/v1/access_tokens` and set a fresh one with `update({ accessToken })` before it expires. Mounting everything needs `ad_campaign:read`/`:create`, `ad_group:read`, `ad:read`, `stats:read`, the `:update`/`:delete` scopes the table's row actions use, `company:basic:read` for the pixel checks `campaign-creator` runs, and `payment:charge` plus `user:email:read` to add an ad-spend card. Mounting fewer surfaces can ask for fewer scopes — still on the one token. Omitted, the calls carry the viewer's own session, which only answers same-origin.
20
+ */
21
+ accessToken?: string;
22
+ /**
23
+ * Where the reporting `table`’s click and result counts link on your site — typically the pages where you mounted the `tracking` namespace’s `people` and `events` elements. `people` and `events` are absolute base URLs (`https://…`); the table appends the same query params those elements take as props (`?source=whop:adcamp_…:*&event=…&from=…&to=…`), so the target page can hydrate its element straight from its URL. A relative URL would resolve against the element frame, so one is treated as unset; unset links render the counts as plain figures.
24
+ * @default {}
25
+ */
26
+ links?: CrossLinksConfig;
27
+ /**
28
+ * The account's ad-spend payment methods changed and the change is saved. Slot values are the method IDs themselves — `payt_…` for a card, `ldgr_…` for a balance; an empty `backup` means none is set.
29
+ */
30
+ onBillingChanged?: ((payload: { primary: string; backup: string; }) => void);
31
+ /**
32
+ * Runs when the grouped loading state changes. The value is `true` while any mounted element is still loading.
33
+ */
34
+ onLoadingChange?: ((loading: boolean) => void);
35
+ /**
36
+ * Set `false` to turn off Whop's built-in usage analytics for this handle and its elements. The analytics identity is never threaded to its frames. A reserved option, not element data.
37
+ */
38
+ analytics?: false;
39
+ /**
40
+ * Visual customization for this group's elements. Overrides the global `WhopElements({ appearance })`. Change it live with `update({ appearance })`.
41
+ */
42
+ appearance?: import("./_framework.js").Appearance;
43
+ /**
44
+ * Locale for this group's element UI text. Set it to one of the app's built locales to override the global configuration. Any other value falls back to the default locale.
45
+ */
46
+ locale?: import("./_framework.js").WhopElementsLocale;
47
+ }
48
+
49
+ /**
50
+ * Consumer props for the "billing-setup" element. Set at create (or as `<BillingSetupElement />` JSX props), and updatable live via `update()`.
51
+ * @see https://docs.whop.com/elements/latest/ads/billing-setup
52
+ */
53
+ export interface BillingSetupElementProps {}
54
+
55
+ /**
56
+ * The live handle for a mounted "billing-setup" element. Returned by `create("billing-setup")`; in React, the component's `ref`.
57
+ * @see https://docs.whop.com/elements/latest/ads/billing-setup
58
+ */
59
+ export interface BillingSetupElementHandle {
60
+ /**
61
+ * Mounts the element in `target` and starts loading. React components mount themselves.
62
+ */
63
+ mount: (target: string | HTMLElement) => void;
64
+ /**
65
+ * Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.
66
+ */
67
+ destroy: () => void;
68
+ /**
69
+ * Merges new props into the mounted element. In React, change the component props instead.
70
+ */
71
+ update: (options: Partial<BillingSetupElementProps>) => void;
72
+ }
73
+
74
+ /**
75
+ * Options for `create("billing-setup")`: the consumer props plus event callbacks and lifecycle hooks.
76
+ * @example
77
+ * ```ts
78
+ * const billing_setup = ads.create("billing-setup", {}); // this interface: props + on<Event> callbacks
79
+ * billing_setup.mount("#ads-billing-setup");
80
+ * ```
81
+ * @see https://docs.whop.com/elements/latest/ads/billing-setup
82
+ */
83
+ export interface BillingSetupElementCreateOptions {
84
+ /**
85
+ * Runs after the loading skeleton first paints and before `onReady`.
86
+ */
87
+ onLoaderStart?: (() => void);
88
+ /**
89
+ * Runs after the element's first complete paint.
90
+ */
91
+ onReady?: (() => void);
92
+ /**
93
+ * Runs when the element fails to load or crashes. The fallback remains visible. Use `code` for programmatic handling. `sourceKey` identifies a failed host-state source.
94
+ */
95
+ onError?: ((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void);
96
+ }
97
+
98
+ /**
99
+ * Consumer props for the "campaign-creator" element. Set at create (or as `<CampaignCreatorElement />` JSX props), and updatable live via `update()`.
100
+ * @see https://docs.whop.com/elements/latest/ads/campaign-creator
101
+ */
102
+ export interface CampaignCreatorElementProps {
103
+ /**
104
+ * The campaign (`adcamp_…`) to open. Empty builds a new one. A draft opens where it was left off; a launched campaign opens in edit mode.
105
+ * @default ""
106
+ */
107
+ campaignId?: string;
108
+ /**
109
+ * The ad group (`adgrp_…`) to open in focus, within `campaignId`. Ignored when the campaign has no such group, and when `campaignId` is empty.
110
+ * @default ""
111
+ */
112
+ adGroupId?: string;
113
+ /**
114
+ * The ad (`ad_…`) to open in focus, within `adGroupId`. Ignored when that group has no such ad, and when `adGroupId` is empty.
115
+ * @default ""
116
+ */
117
+ adId?: string;
118
+ /**
119
+ * Which step to open on: `campaign-settings`, `ad-groups`, or `ads`. The dashboard deep-links this off its own URL; pass it to drop an account owner straight onto the part they came to change. Read once at mount — moving it later will not walk them between steps.
120
+ * @default "campaign-settings"
121
+ */
122
+ initialStep?: "ads" | "ad-groups" | "campaign-settings";
123
+ }
124
+
125
+ /**
126
+ * The live handle for a mounted "campaign-creator" element. Returned by `create("campaign-creator")`; in React, the component's `ref`.
127
+ * @see https://docs.whop.com/elements/latest/ads/campaign-creator
128
+ */
129
+ export interface CampaignCreatorElementHandle {
130
+ /**
131
+ * Mounts the element in `target` and starts loading. React components mount themselves.
132
+ */
133
+ mount: (target: string | HTMLElement) => void;
134
+ /**
135
+ * Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.
136
+ */
137
+ destroy: () => void;
138
+ /**
139
+ * Merges new props into the mounted element. In React, change the component props instead.
140
+ */
141
+ update: (options: Partial<CampaignCreatorElementProps>) => void;
142
+ }
143
+
144
+ /**
145
+ * Options for `create("campaign-creator")`: the consumer props plus event callbacks and lifecycle hooks.
146
+ * @example
147
+ * ```ts
148
+ * const campaign_creator = ads.createOverlay("campaign-creator", {}); // this interface: props + on<Event> callbacks
149
+ * campaign_creator.open();
150
+ * ```
151
+ * @see https://docs.whop.com/elements/latest/ads/campaign-creator
152
+ */
153
+ export interface CampaignCreatorElementCreateOptions {
154
+ /**
155
+ * The campaign (`adcamp_…`) to open. Empty builds a new one. A draft opens where it was left off; a launched campaign opens in edit mode.
156
+ * @default ""
157
+ */
158
+ campaignId?: string;
159
+ /**
160
+ * The ad group (`adgrp_…`) to open in focus, within `campaignId`. Ignored when the campaign has no such group, and when `campaignId` is empty.
161
+ * @default ""
162
+ */
163
+ adGroupId?: string;
164
+ /**
165
+ * The ad (`ad_…`) to open in focus, within `adGroupId`. Ignored when that group has no such ad, and when `adGroupId` is empty.
166
+ * @default ""
167
+ */
168
+ adId?: string;
169
+ /**
170
+ * Which step to open on: `campaign-settings`, `ad-groups`, or `ads`. The dashboard deep-links this off its own URL; pass it to drop an account owner straight onto the part they came to change. Read once at mount — moving it later will not walk them between steps.
171
+ * @default "campaign-settings"
172
+ */
173
+ initialStep?: "ads" | "ad-groups" | "campaign-settings";
174
+ /**
175
+ * The account owner backed out of the builder without launching. Nothing has been discarded — a draft campaign, if one was started, is already saved. An overlay has already closed itself by the time this fires; react to it if your page needs to.
176
+ */
177
+ onExited?: ((payload: Record<string, never>) => void);
178
+ /**
179
+ * A campaign went live. `firstLaunch` marks the account’s first ever launched campaign, which is what the dashboard uses to show its welcome state. An overlay has already closed itself; this is where you route onward.
180
+ */
181
+ onLaunched?: ((payload: { campaignId: string; firstLaunch: boolean; }) => void);
182
+ /**
183
+ * Runs after the loading skeleton first paints and before `onReady`.
184
+ */
185
+ onLoaderStart?: (() => void);
186
+ /**
187
+ * Runs after the element's first complete paint.
188
+ */
189
+ onReady?: (() => void);
190
+ /**
191
+ * Runs when the element fails to load or crashes. The fallback remains visible. Use `code` for programmatic handling. `sourceKey` identifies a failed host-state source.
192
+ */
193
+ onError?: ((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void);
194
+ }
195
+
196
+ /**
197
+ * The overlay handle for "campaign-creator". Returned by `createOverlay("campaign-creator")`; drives the modal presentation imperatively.
198
+ * @see https://docs.whop.com/elements/latest/ads/campaign-creator
199
+ */
200
+ export interface CampaignCreatorElementOverlayHandle {
201
+ /**
202
+ * Open the overlay. The first call mounts the element. Later calls reuse it.
203
+ */
204
+ open(): void;
205
+ /**
206
+ * Close the overlay without destroying it. Keep the handle and `open()` again.
207
+ */
208
+ close(): void;
209
+ /**
210
+ * Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.
211
+ */
212
+ destroy(): void;
213
+ /**
214
+ * Merges new props into the mounted element. In React, change the component props instead.
215
+ */
216
+ update(options: Partial<CampaignCreatorElementProps>): void;
217
+ }
218
+
219
+ /**
220
+ * Consumer props for the "reporting" sub-controller: the `create("reporting")` options and the minted sub handle's `update()` payload (React: `<Reporting>` props). Parent-injected props never appear here.
221
+ * @see https://docs.whop.com/elements/latest/ads/overview
222
+ */
223
+ export interface ReportingSubOptions {
224
+ /**
225
+ * The window every surface reports on: `today`, `yesterday`, `last_7_days`, `last_14_days`, `last_30_days`, `last_90_days`, `all_time`, or `custom` (pair it with `customRange`). The chart carries the picker, and it moves this — so a host can drive the window and read it back off `periodChanged`.
226
+ * @default "last_14_days"
227
+ */
228
+ period?: "today" | "yesterday" | "last_7_days" | "last_14_days" | "last_30_days" | "last_90_days" | "all_time" | "custom";
229
+ /**
230
+ * The explicit window, as ISO 8601 instants, used when `period` is `custom`. Ignored otherwise.
231
+ * @default null
232
+ */
233
+ customRange?: { from: string; to: string; } | null;
234
+ /**
235
+ * Timezone choice for every reported figure. Use `account` for the account's `preferences.ads_scheduling_timezone` or `local` for the viewer's browser timezone. These are the only choices the chart offers. A free-form IANA timezone could make the picker label data incorrectly and would be lost when the viewer changes the selection. To report in another timezone, change the account setting. `account` falls back to the viewer's timezone when the account has no setting.
236
+ * @default "account"
237
+ */
238
+ timezone?: "account" | "local";
239
+ /**
240
+ * Lowercase three-letter ISO 4217 currency code for converted amounts, such as `usd` or `eur`. Unset, it defaults to the account's `preferences.ads_reporting_currency`.
241
+ * @default ""
242
+ */
243
+ currency?: string;
244
+ /**
245
+ * Which touch in a buyer’s journey gets the credit: `last_touch`, the default, or `first_touch`. Under both, a Whop touch anywhere in the journey wins the Whop bucket — the model only picks the endpoints. The table carries the picker and moves this, so a host can drive it and read it back off `attributionModelChanged`.
246
+ * @default "last_touch"
247
+ */
248
+ attributionModel?: "last_touch" | "first_touch";
249
+ /**
250
+ * Narrow reporting to these ad campaigns (`adcamp_…`). Empty reports on the whole account. Overridden by `adGroupIds` or `adIds` when either is set. **Pass one ID for an exact figure:** the reporting API scopes by a single source path, so where more than one is given the chart reports on the first alone.
251
+ * @default []
252
+ */
253
+ campaignIds?: string[];
254
+ /**
255
+ * Narrow reporting to these ad groups (`adgrp_…`). Takes precedence over `campaignIds`. Same single-ID caveat.
256
+ * @default []
257
+ */
258
+ adGroupIds?: string[];
259
+ /**
260
+ * Narrow reporting to these ads (`ad_…`). The narrowest filter — takes precedence over both others. Same single-ID caveat.
261
+ * @default []
262
+ */
263
+ adIds?: string[];
264
+ /**
265
+ * Which table the `table` element opens on: `campaigns`, `ad-groups`, `ads`, or `all` for the traffic-source view. `all` always reports account-wide — the source series exists only at that level — so a filter set alongside it narrows the table but not the chart.
266
+ * @default "campaigns"
267
+ */
268
+ tab?: "ads" | "all" | "campaigns" | "ad-groups";
269
+ /**
270
+ * Which traffic the chart reports on, as source paths — `whop:*` for advertising bought through Whop, `ext:*` and `ext:<platform>:*` for ads run elsewhere, `referrer:*` for organic, `direct`, `other`. `null`, the default, reports on Whop advertising alone; `[]` reports on every source; a non-empty array reports on those. A DIFFERENT axis to `campaignIds` and friends, which narrow within Whop advertising — spend-derived ratios stay Whop-attributed whatever this is set to, because spend only ever bought Whop ads. The `table` element’s All tab moves it.
271
+ * @default null
272
+ */
273
+ sources?: string[] | null;
274
+ /**
275
+ * The viewer asked to edit something — a row menu, a draft row, or Edit ad in the details overlay. `campaignId` is always there; `adGroupId` and `adId` narrow it to what they clicked. Only raised when `useCampaignCreator` is off; on, the builder opens over the page instead and this stays quiet.
276
+ */
277
+ onEditRequested?: ((payload: AdsEditTarget) => void);
278
+ }
279
+
280
+ /**
281
+ * Consumer props for the "reporting" sub-controller's "chart" element.
282
+ * @see https://docs.whop.com/elements/latest/ads/overview
283
+ */
284
+ export interface ChartElementProps {
285
+ /**
286
+ * What the chart plots — `spend`, `impressions`, `clicks`, or a conversion. The picker moves it; set it to open on something else. For `conversions`, `conversion_value` and `cost_per_conversion`, name the conversion in `metricEvent`.
287
+ * @default "spend"
288
+ */
289
+ metric?: "funnel" | "spend" | "impressions" | "clicks" | "cost_per_1k_impressions" | "cost_per_click" | "conversions" | "conversion_value" | "cost_per_conversion";
290
+ /**
291
+ * The conversion `metric` refers to when it is a per-conversion one — `payment.completed`, `pixel.lead`, or a custom event the account names itself. Ignored by every other metric.
292
+ * @default ""
293
+ */
294
+ metricEvent?: string;
295
+ }
296
+
297
+ /**
298
+ * The live handle for a mounted "chart" element. Returned by the "reporting" sub handle's `create("chart")`.
299
+ * @see https://docs.whop.com/elements/latest/ads/overview
300
+ */
301
+ export interface ChartElementHandle {
302
+ /**
303
+ * Mounts the element in `target` and starts loading. React components mount themselves.
304
+ */
305
+ mount: (target: string | HTMLElement) => void;
306
+ /**
307
+ * Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.
308
+ */
309
+ destroy: () => void;
310
+ /**
311
+ * Merges new props into the mounted element. In React, change the component props instead.
312
+ */
313
+ update: (options: Partial<ChartElementProps>) => void;
314
+ }
315
+
316
+ /**
317
+ * Options for the "reporting" sub handle's `create("chart")`: the consumer props plus event callbacks and lifecycle hooks.
318
+ * @see https://docs.whop.com/elements/latest/ads/overview
319
+ */
320
+ export interface ChartElementCreateOptions {
321
+ /**
322
+ * What the chart plots — `spend`, `impressions`, `clicks`, or a conversion. The picker moves it; set it to open on something else. For `conversions`, `conversion_value` and `cost_per_conversion`, name the conversion in `metricEvent`.
323
+ * @default "spend"
324
+ */
325
+ metric?: "funnel" | "spend" | "impressions" | "clicks" | "cost_per_1k_impressions" | "cost_per_click" | "conversions" | "conversion_value" | "cost_per_conversion";
326
+ /**
327
+ * The conversion `metric` refers to when it is a per-conversion one — `payment.completed`, `pixel.lead`, or a custom event the account names itself. Ignored by every other metric.
328
+ * @default ""
329
+ */
330
+ metricEvent?: string;
331
+ /**
332
+ * The viewer picked a different result to plot. `metric` is what is being plotted; `event` names the conversion it refers to, and is present only for `conversions`, `conversion_value` and `cost_per_conversion` — the account decides what those are called, so it is a string rather than a member. Mirror it into your own URL and hand it back as `metric`/`metricEvent` if you want the choice to survive a reload; the element holds it for the life of the mount either way.
333
+ */
334
+ onMetricChanged?: ((payload: { metric: "funnel" | "spend" | "impressions" | "clicks" | "cost_per_1k_impressions" | "cost_per_click" | "conversions" | "conversion_value" | "cost_per_conversion"; event?: string | undefined; }) => void);
335
+ /**
336
+ * The viewer switched which zone the figures are reported in: the choice they made AND the IANA zone it resolves to. The choice is the half that survives a reload — persist it and pass it back as `timezone`, which is what the Whop dashboard does with its own copy; the element holds it for the life of the mount either way. `resolved` comes along so a host can label its own figures without repeating the account-preference lookup, and is the viewer's own zone whenever the account has set none.
337
+ */
338
+ onTimezoneChanged?: ((payload: { timezone: "account" | "local"; resolved: string; }) => void);
339
+ /**
340
+ * The viewer moved the reporting window: the period they picked AND the window it resolves to, as ISO 8601 instants. The dates come resolved because a period name alone would leave you redoing the day-boundary and account-timezone arithmetic to act on it; the period comes too because only it survives a reload as a ROLLING window — stored dates would pin it. Every surface under the same handle has already followed the move.
341
+ */
342
+ onPeriodChanged?: ((payload: { period: "today" | "yesterday" | "last_7_days" | "last_14_days" | "last_30_days" | "last_90_days" | "all_time" | "custom"; from: string; to: string; }) => void);
343
+ /**
344
+ * Runs after the loading skeleton first paints and before `onReady`.
345
+ */
346
+ onLoaderStart?: (() => void);
347
+ /**
348
+ * Runs after the element's first complete paint.
349
+ */
350
+ onReady?: (() => void);
351
+ /**
352
+ * Runs when the element fails to load or crashes. The fallback remains visible. Use `code` for programmatic handling. `sourceKey` identifies a failed host-state source.
353
+ */
354
+ onError?: ((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void);
355
+ }
356
+
357
+ /**
358
+ * Consumer props for the "reporting" sub-controller's "table" element.
359
+ * @see https://docs.whop.com/elements/latest/ads/overview
360
+ */
361
+ export interface TableElementProps {
362
+ /**
363
+ * What happens when a viewer asks to edit — from a row menu, a draft row, or Edit ad in the details overlay. On by default: the campaign builder opens over the page, on the campaign and step they asked for, so editing works with nothing wired up. Turn it off to handle campaign editing yourself — nothing opens, and the request comes back on `editRequested`.
364
+ * @default true
365
+ */
366
+ useCampaignCreator?: boolean;
367
+ /**
368
+ * How rows are broken down — by country, platform, placement — or `null` for whole rows.
369
+ * @default null
370
+ */
371
+ breakdown?: "age" | "gender" | "age_gender" | "placement" | "publisher_platform" | "device_platform" | "impression_device" | "country" | "region" | "hour" | null;
372
+ /**
373
+ * The columns on show, by name — standard ones like `impressions` and `roas`, and any pixel events the viewer added. Unset, the table opens on its own defaults. Comes back whole on `columnsChanged`; store the list and pass it here to have the layout stick.
374
+ * @default null
375
+ */
376
+ columns?: string[] | null;
377
+ /**
378
+ * Columns computed from the figures already in the table — a formula that you name and format. The table can edit them, and every change comes back on `customMetricsChanged` as the whole new list; persist it and pass it here to have it stick.
379
+ * @default []
380
+ */
381
+ customMetrics?: CustomMetricDefinition[];
382
+ /**
383
+ * What the All tab is drilled into, as a source path: `null` for the roots, `ext:*` for a platform list, `ext:<platform>:*` for that platform’s campaigns. Comes back on `viewChanged`.
384
+ * @default null
385
+ */
386
+ sourcesDrill?: string | null;
387
+ /**
388
+ * What the Ads tab’s search box is filtered to.
389
+ * @default ""
390
+ */
391
+ query?: string;
392
+ /**
393
+ * Whether paused campaigns are listed.
394
+ * @default true
395
+ */
396
+ showPausedCampaigns?: boolean;
397
+ }
398
+
399
+ /**
400
+ * The live handle for a mounted "table" element. Returned by the "reporting" sub handle's `create("table")`.
401
+ * @see https://docs.whop.com/elements/latest/ads/overview
402
+ */
403
+ export interface TableElementHandle {
404
+ /**
405
+ * Mounts the element in `target` and starts loading. React components mount themselves.
406
+ */
407
+ mount: (target: string | HTMLElement) => void;
408
+ /**
409
+ * Removes the element and releases its frame and subscriptions. You can call it more than once. React removes the element automatically.
410
+ */
411
+ destroy: () => void;
412
+ /**
413
+ * Merges new props into the mounted element. In React, change the component props instead.
414
+ */
415
+ update: (options: Partial<TableElementProps>) => void;
416
+ }
417
+
418
+ /**
419
+ * Options for the "reporting" sub handle's `create("table")`: the consumer props plus event callbacks and lifecycle hooks.
420
+ * @see https://docs.whop.com/elements/latest/ads/overview
421
+ */
422
+ export interface TableElementCreateOptions {
423
+ /**
424
+ * What happens when a viewer asks to edit — from a row menu, a draft row, or Edit ad in the details overlay. On by default: the campaign builder opens over the page, on the campaign and step they asked for, so editing works with nothing wired up. Turn it off to handle campaign editing yourself — nothing opens, and the request comes back on `editRequested`.
425
+ * @default true
426
+ */
427
+ useCampaignCreator?: boolean;
428
+ /**
429
+ * How rows are broken down — by country, platform, placement — or `null` for whole rows.
430
+ * @default null
431
+ */
432
+ breakdown?: "age" | "gender" | "age_gender" | "placement" | "publisher_platform" | "device_platform" | "impression_device" | "country" | "region" | "hour" | null;
433
+ /**
434
+ * The columns on show, by name — standard ones like `impressions` and `roas`, and any pixel events the viewer added. Unset, the table opens on its own defaults. Comes back whole on `columnsChanged`; store the list and pass it here to have the layout stick.
435
+ * @default null
436
+ */
437
+ columns?: string[] | null;
438
+ /**
439
+ * Columns computed from the figures already in the table — a formula that you name and format. The table can edit them, and every change comes back on `customMetricsChanged` as the whole new list; persist it and pass it here to have it stick.
440
+ * @default []
441
+ */
442
+ customMetrics?: CustomMetricDefinition[];
443
+ /**
444
+ * What the All tab is drilled into, as a source path: `null` for the roots, `ext:*` for a platform list, `ext:<platform>:*` for that platform’s campaigns. Comes back on `viewChanged`.
445
+ * @default null
446
+ */
447
+ sourcesDrill?: string | null;
448
+ /**
449
+ * What the Ads tab’s search box is filtered to.
450
+ * @default ""
451
+ */
452
+ query?: string;
453
+ /**
454
+ * Whether paused campaigns are listed.
455
+ * @default true
456
+ */
457
+ showPausedCampaigns?: boolean;
458
+ /**
459
+ * The open tab changed. Mirror it into your own URL if you want it to survive a reload.
460
+ */
461
+ onTabChanged?: ((payload: { tab: "ads" | "all" | "campaigns" | "ad-groups"; }) => void);
462
+ /**
463
+ * The viewer narrowed the view — by ticking rows, or by clicking through a campaign to its ad groups. Every surface under the same handle has already followed it.
464
+ */
465
+ onFilterChanged?: ((payload: { campaignIds: string[]; adGroupIds: string[]; adIds: string[]; }) => void);
466
+ /**
467
+ * The viewer showed or hid a column. Carries every column now on show, standard and pixel-event alike — store the list and pass it straight back as `columns`, or the layout resets on the next mount.
468
+ */
469
+ onColumnsChanged?: ((payload: { columns: string[]; }) => void);
470
+ /**
471
+ * The viewer added, edited, or removed a computed column. Carries the entire list either way — store it as given and pass it back as `customMetrics`, or they are gone on the next mount.
472
+ */
473
+ onCustomMetricsChanged?: ((payload: { customMetrics: CustomMetricDefinition[]; }) => void);
474
+ /**
475
+ * The viewer moved one of the table’s own controls — the All tab’s drill, the breakdown, the search box, the paused toggle. Carries all four whichever moved; store them and pass them back as props, or they reset on the next mount.
476
+ */
477
+ onViewChanged?: ((payload: { sourcesDrill: string | null; breakdown: "age" | "gender" | "age_gender" | "placement" | "publisher_platform" | "device_platform" | "impression_device" | "country" | "region" | "hour" | null; query: string; showPausedCampaigns: boolean; }) => void);
478
+ /**
479
+ * What the All tab is now looking at, as source paths ready to hand to a chart: `null` off the All tab (Whop advertising alone), `[]` for every source, otherwise the ticked rows or the drilled-into group. Every surface under the same handle has already followed it.
480
+ */
481
+ onSourcesChanged?: ((payload: { sources: string[] | null; }) => void);
482
+ /**
483
+ * The viewer changed which touch gets the credit, from the picker on the All tab. Every surface under the same handle has already re-credited; persist it and pass it back as `attributionModel`, or it reverts to last touch on the next mount.
484
+ */
485
+ onAttributionModelChanged?: ((payload: { attributionModel: "last_touch" | "first_touch"; }) => void);
486
+ /**
487
+ * Runs after the loading skeleton first paints and before `onReady`.
488
+ */
489
+ onLoaderStart?: (() => void);
490
+ /**
491
+ * Runs after the element's first complete paint.
492
+ */
493
+ onReady?: (() => void);
494
+ /**
495
+ * Runs when the element fails to load or crashes. The fallback remains visible. Use `code` for programmatic handling. `sourceKey` identifies a failed host-state source.
496
+ */
497
+ onError?: ((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void);
498
+ }
499
+
500
+ /**
501
+ * The "reporting" sub-handle, minted by `handle.create("reporting", …)`. Mounts the sub-controller's elements and carries its actions.
502
+ * @see https://docs.whop.com/elements/latest/ads/overview
503
+ */
504
+ export interface ReportingSubHandle {
505
+ /**
506
+ * An account’s performance over a window, with a picker for what to plot — spend, impressions, clicks, or any conversion the account records. Read-only.
507
+ */
508
+ create(name: "chart", options?: ChartElementCreateOptions): ChartElementHandle;
509
+ /**
510
+ * An advertising account's campaigns, ad groups, and ads in one table, with the tabs that move between them: pick rows to narrow the level below, search, sort, break the numbers down, choose your columns, and pause, resume, duplicate, or delete straight from a row. The window it reports on and the rows it is filtered to live on the handle, so a chart mounted beside it reports on exactly the same thing.
511
+ */
512
+ create(name: "table", options?: TableElementCreateOptions): TableElementHandle;
513
+ /**
514
+ * Merges new props and callbacks into the sub-controller.
515
+ */
516
+ update(options: Partial<ReportingSubOptions>): void;
517
+ /**
518
+ * Destroys the sub-controller and its elements, then frees its exclusive slot. A later `create("reporting")` starts fresh.
519
+ */
520
+ destroy(): void;
521
+ }
522
+
523
+ /**
524
+ * The Ads handle, returned by `whop.ads.create()` (React: `useAds()`). Mounts the elements and carries the controller's actions.
525
+ * @see https://docs.whop.com/elements/latest/ads/overview
526
+ */
527
+ export interface AdsHandle {
528
+ /**
529
+ * Which payment methods ad spend bills against: a primary used first, and an optional backup for when it fails. Both are chosen from the methods already saved on the account, and picking one saves it immediately — there is no separate submit. Adding a card opens a card form over your page and returns to the slot that asked for it. The account's own balance appears alongside its cards wherever the account has one.
530
+ */
531
+ create(name: "billing-setup", options?: BillingSetupElementCreateOptions): BillingSetupElementHandle;
532
+ /**
533
+ * The advertising campaign builder: objective and budget, ad groups with their targeting and schedule, and the ads themselves with their creative — the whole flow through to launch. Opens empty to build a new campaign, or on an existing one when you pass `campaignId`. It runs the pixel checker too: a launch is gated on the ad group’s conversion event being live on the destination URL, and the `pixel-setup` wizard opens inside this element to fix an install that is missing. The one token you set on the `ads` handle must carry the pixel scopes alongside the campaign scopes — `ad_campaign:create` and `company:basic:read` — rather than using a separate token per element.
534
+ */
535
+ createOverlay(name: "campaign-creator", options?: CampaignCreatorElementCreateOptions): CampaignCreatorElementOverlayHandle;
536
+ /**
537
+ * An advertising account's reporting: what it spent and what came back, over a window, at whatever level you narrow to. Mount `chart`, `table`, or both — they read the same window, the same credit rule, and the same selection, so two surfaces side by side can never disagree about what they are showing. The `ads` handle's `links` configuration wires the table's click and result counts to your own pages — the ones where you mounted the `tracking` namespace's `people` and `events`.
538
+ */
539
+ create(name: "reporting", options?: ReportingSubOptions): ReportingSubHandle;
540
+ /**
541
+ * Merges new handle options into every mounted element. In React, change the namespace props instead.
542
+ */
543
+ update(options: Partial<AdsOptions>): void;
544
+ /**
545
+ * Destroys every element and sub-controller this handle created, removes the controller frame, and releases its subscriptions. You can call it more than once, but a destroyed handle refuses any other call — create a new handle to start over. React removes the group automatically when the provider unmounts.
546
+ */
547
+ destroy(): void;
548
+ }
549
+
550
+ /**
551
+ * Ads's static actions, callable with nothing mounted: `whop.ads.<method>()` (React: `useWhop().ads.<method>()`).
552
+ * @see https://docs.whop.com/elements/latest/ads/overview
553
+ */
554
+ export interface AdsStatics {}
555
+
556
+ /**
557
+ * The consumer-facing shape of an element's `links` prop. `people`/`events` are base URLs the canonical query params are appended to; `person` is a template whose `{personId}` and `{identifier}` placeholders are replaced with the row's URL-encoded values.
558
+ * Declared from the app's `CrossLinksConfig`, referenced by a host-capability surface.
559
+ */
560
+ export interface CrossLinksConfig {
561
+ people?: string | undefined;
562
+ events?: string | undefined;
563
+ person?: string | undefined;
564
+ }
565
+
566
+ /**
567
+ * What a builder href asks to edit, once it has been read back out of the route.
568
+ * Declared from the app's `AdsEditTarget`, referenced by a host-capability surface.
569
+ */
570
+ export interface AdsEditTarget {
571
+ campaignId: string;
572
+ adGroupId?: string | undefined;
573
+ adId?: string | undefined;
574
+ }
575
+
576
+ /**
577
+ * A computed column as anyone outside this module needs it. `id` is deliberately absent — it is a within-render column key (`customMetricColumnVisibility`), never persisted and never meaningful to a caller, so it is minted on the way in rather than carried around.
578
+ * Declared from the app's `CustomMetricDefinition`, referenced by a host-capability surface.
579
+ */
580
+ export interface CustomMetricDefinition {
581
+ name: string;
582
+ formula: string;
583
+ format: "number" | "currency" | "percent";
584
+ enabled: boolean;
585
+ }