trackrev 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +988 -42
  2. package/package.json +21 -3
  3. package/src/commands/affiliates.js +162 -0
  4. package/src/commands/analytics.js +128 -0
  5. package/src/commands/attribution.js +55 -0
  6. package/src/commands/auth.js +41 -0
  7. package/src/commands/domains.js +60 -0
  8. package/src/commands/folders.js +69 -0
  9. package/src/commands/keys.js +54 -0
  10. package/src/commands/links.js +203 -0
  11. package/src/commands/me.js +25 -0
  12. package/src/commands/money.js +96 -0
  13. package/src/commands/people.js +94 -0
  14. package/src/commands/retargeting.js +49 -0
  15. package/src/commands/revenue.js +87 -0
  16. package/src/commands/settings.js +64 -0
  17. package/src/commands/webhooks.js +79 -0
  18. package/src/index.js +43 -294
  19. package/src/lib/api.js +87 -0
  20. package/src/lib/config.js +52 -0
  21. package/src/lib/output.js +95 -0
  22. package/src/lib/prompt.js +55 -0
  23. package/src/registry.d.ts +58 -0
  24. package/src/registry.js +840 -0
  25. package/src/sdk/client.js +177 -0
  26. package/src/sdk/index.d.ts +534 -0
  27. package/src/sdk/index.js +1 -0
  28. package/src/sdk/resources/attribution.js +20 -0
  29. package/src/sdk/resources/channels.js +16 -0
  30. package/src/sdk/resources/clicks.js +16 -0
  31. package/src/sdk/resources/commissions.js +40 -0
  32. package/src/sdk/resources/credits.js +23 -0
  33. package/src/sdk/resources/domains.js +35 -0
  34. package/src/sdk/resources/export.js +15 -0
  35. package/src/sdk/resources/folders.js +55 -0
  36. package/src/sdk/resources/keys.js +28 -0
  37. package/src/sdk/resources/links.js +131 -0
  38. package/src/sdk/resources/orders.js +15 -0
  39. package/src/sdk/resources/partners.js +37 -0
  40. package/src/sdk/resources/payouts.js +22 -0
  41. package/src/sdk/resources/programs.js +55 -0
  42. package/src/sdk/resources/referrals.js +83 -0
  43. package/src/sdk/resources/retargeting.js +23 -0
  44. package/src/sdk/resources/revenue.js +53 -0
  45. package/src/sdk/resources/settings.js +29 -0
  46. package/src/sdk/resources/visitors.js +25 -0
  47. package/src/sdk/resources/webhooks.js +41 -0
@@ -0,0 +1,534 @@
1
+ /**
2
+ * Type definitions for the TrackRev SDK.
3
+ *
4
+ * Hand-written, and the reason an editor can autocomplete `trackrev.links.`
5
+ * and underline a misspelled option before the code ever runs.
6
+ *
7
+ * What is typed here is everything you SEND: the method names, which arguments
8
+ * are required, and the exact spelling of every option. What comes back is
9
+ * typed as `ApiResult`, because response shapes belong to the API and are
10
+ * documented at https://trackrev.io/docs — pass a type of your own when you
11
+ * want one checked:
12
+ *
13
+ * const link = (await trackrev.links.get("summer")) as MyLink;
14
+ */
15
+ /** The SDK's own version, e.g. "0.3.0". Matches package.json. */
16
+ export const VERSION: string;
17
+ /** A decoded JSON response. Fields are reached without a compile-time check. */
18
+ export type ApiResult = Record<string, any>;
19
+
20
+ /** YYYY-MM-DD. */
21
+ export type DateString = string;
22
+
23
+ /** An ISO 8601 timestamp, e.g. "2026-09-24T10:00:00.000Z". */
24
+ export type Timestamp = string;
25
+
26
+ export interface TrackRevOptions {
27
+ /** Defaults to "https://app.trackrev.io/api/v1". */
28
+ apiUrl?: string;
29
+ /** Give up on one attempt after this long. 0 means no limit. Default 15000. */
30
+ timeoutMs?: number;
31
+ /** Retries after the first attempt, for requests that are safe to repeat. Default 3. */
32
+ maxRetries?: number;
33
+ }
34
+
35
+ /**
36
+ * Any answer from the API that was not a success: a bad request, a missing
37
+ * key, a plan gate, a rate limit, a server fault.
38
+ */
39
+ export class TrackRevError extends Error {
40
+ constructor(init: { status: number; code: string; message: string });
41
+ name: string;
42
+ /** The HTTP status, or 0 when the request never got an answer. */
43
+ status: number;
44
+ /** The API's own code, e.g. "bad_request", "unauthorized", "plan_required". */
45
+ code: string;
46
+ /** Present on a 429 that carried a Retry-After header. */
47
+ retryAfterMs?: number;
48
+ }
49
+
50
+ /** The request never got an answer: the server was unreachable, or it timed out. */
51
+ export class TrackRevConnectionError extends TrackRevError {
52
+ constructor(message: string);
53
+ status: 0;
54
+ code: "connection_error";
55
+ }
56
+
57
+ /* ── Shared option shapes ─────────────────────────────────────────────────── */
58
+
59
+ /** A reporting window: `days`, or `from`/`to`. */
60
+ export interface WindowOptions {
61
+ /** Default 30. */
62
+ days?: number;
63
+ from?: DateString;
64
+ to?: DateString;
65
+ }
66
+
67
+ /** Cursor paging: pass the `next_cursor` the previous call returned. */
68
+ export interface PageOptions {
69
+ limit?: number;
70
+ cursor?: string;
71
+ }
72
+
73
+ /* ── Values the API validates ─────────────────────────────────────────────── */
74
+
75
+ export type AttributionModel = "last_touch" | "first_touch" | "linear";
76
+ export type CommissionStatus = "pending" | "eligible" | "paid" | "refunded" | "void" | "fraud";
77
+ export type CommissionType = "percent" | "flat";
78
+ export type ProgramStatus = "active" | "paused" | "archived";
79
+ export type PartnerStatus = "pending" | "approved" | "rejected" | "banned" | "archived";
80
+ export type CreditStatus = "earned" | "delivered" | "all";
81
+ export type KeyScope = "secret" | "public";
82
+ export type ReferrerTier = "free" | "paid";
83
+ export type RewardMode = "referrer" | "affiliate";
84
+ export type ExportKind = "channels" | "links" | "orders" | "visitors";
85
+
86
+ /* ── attribution ──────────────────────────────────────────────────────────── */
87
+
88
+ export interface AttributionResource {
89
+ /** The workspace's model and lookback window, plus the catalogue of models. */
90
+ get(): Promise<ApiResult>;
91
+ /** Both settings retroactively change every revenue figure the product reports. */
92
+ update(options?: {
93
+ model?: AttributionModel;
94
+ /** Clamped to 1–365. */
95
+ windowDays?: number;
96
+ }): Promise<ApiResult>;
97
+ }
98
+
99
+ /* ── channels ─────────────────────────────────────────────────────────────── */
100
+
101
+ export interface ChannelsResource {
102
+ /** Performance per traffic source, ranked by revenue. */
103
+ list(options?: WindowOptions & {
104
+ /** Add all-time lifetime value per channel. */
105
+ ltv?: boolean;
106
+ }): Promise<ApiResult>;
107
+ }
108
+
109
+ /* ── clicks ───────────────────────────────────────────────────────────────── */
110
+
111
+ export interface ClicksResource {
112
+ /** The raw click stream, newest first. Bots are excluded unless asked for. */
113
+ list(options?: {
114
+ limit?: number;
115
+ /** The previous call's `next_cursor`; null means you reached the end. */
116
+ before?: string;
117
+ linkId?: string;
118
+ includeBots?: boolean;
119
+ }): Promise<ApiResult>;
120
+ }
121
+
122
+ /* ── commissions ──────────────────────────────────────────────────────────── */
123
+
124
+ export interface CommissionsResource {
125
+ /** The commission ledger, newest first. */
126
+ list(options?: PageOptions & {
127
+ status?: CommissionStatus;
128
+ partnerId?: string;
129
+ }): Promise<ApiResult>;
130
+ /** Record an off-platform deal by hand. `earnings` is what the partner takes home. */
131
+ create(
132
+ programId: string,
133
+ partnerId: string,
134
+ amount: number,
135
+ earnings: number,
136
+ options?: { currency?: string; notes?: string },
137
+ ): Promise<ApiResult>;
138
+ /** Refused once the commission sits in a payout batch. */
139
+ setStatus(id: string | number, status: CommissionStatus): Promise<ApiResult>;
140
+ }
141
+
142
+ /* ── credits ──────────────────────────────────────────────────────────────── */
143
+
144
+ export interface CreditsResource {
145
+ /** Credit grants plus a balance summary. Pass `partnerId` or `externalUserId`. */
146
+ list(options?: {
147
+ partnerId?: string;
148
+ externalUserId?: string;
149
+ /** Default "all". */
150
+ status?: CreditStatus;
151
+ limit?: number;
152
+ }): Promise<ApiResult>;
153
+ /** Confirm a credit was applied in your product. Safe to call twice. */
154
+ markDelivered(id: string): Promise<ApiResult>;
155
+ }
156
+
157
+ /* ── domains ──────────────────────────────────────────────────────────────── */
158
+
159
+ export interface DomainsResource {
160
+ /** Branded domains, each with the DNS records still needed. */
161
+ list(): Promise<ApiResult>;
162
+ get(idOrName: string): Promise<ApiResult>;
163
+ /** Register a branded domain, e.g. "go.brand.com". */
164
+ add(domain: string): Promise<ApiResult>;
165
+ /** Re-check DNS now and return the fresh status. */
166
+ verify(idOrName: string): Promise<ApiResult>;
167
+ /** Links keep working: slugs resolve on the default short host. */
168
+ remove(idOrName: string): Promise<ApiResult>;
169
+ }
170
+
171
+ /* ── export ───────────────────────────────────────────────────────────────── */
172
+
173
+ export interface ExportResource {
174
+ /** Comes back as CSV text, not JSON. */
175
+ csv(kind: ExportKind, options?: WindowOptions): Promise<string>;
176
+ }
177
+
178
+ /* ── folders ──────────────────────────────────────────────────────────────── */
179
+
180
+ export interface FoldersResource {
181
+ /** Campaign folders, each with how many campaigns it holds. */
182
+ list(): Promise<ApiResult>;
183
+ get(id: string): Promise<ApiResult>;
184
+ create(
185
+ name: string,
186
+ options?: {
187
+ description?: string;
188
+ startDate?: DateString;
189
+ endDate?: DateString;
190
+ },
191
+ ): Promise<ApiResult>;
192
+ /** Only the fields you pass change. */
193
+ update(
194
+ id: string,
195
+ options?: {
196
+ name?: string;
197
+ description?: string;
198
+ startDate?: DateString;
199
+ endDate?: DateString;
200
+ },
201
+ ): Promise<ApiResult>;
202
+ /** The campaigns inside are not deleted — they move back to ungrouped. */
203
+ remove(id: string): Promise<ApiResult>;
204
+ /**
205
+ * File a campaign into a folder. `destinationId` is a campaign (the
206
+ * destination behind a set of links), not a single link. Pass null to un-file.
207
+ */
208
+ assign(destinationId: string, folderId: string | null): Promise<ApiResult>;
209
+ }
210
+
211
+ /* ── keys ─────────────────────────────────────────────────────────────────── */
212
+
213
+ export interface KeysResource {
214
+ /** Prefixes and metadata only — never the key itself. */
215
+ list(options?: { includeRevoked?: boolean }): Promise<ApiResult>;
216
+ /** The plaintext key comes back ONCE, as `secret`. A lost key is re-issued, never recovered. */
217
+ create(options?: { scope?: KeyScope; label?: string }): Promise<ApiResult>;
218
+ /** The row stays so `last_used_at` survives for the audit trail. */
219
+ revoke(id: string): Promise<ApiResult>;
220
+ }
221
+
222
+ /* ── links ────────────────────────────────────────────────────────────────── */
223
+
224
+ /** Where a click goes, by where it came from. */
225
+ export interface LinkTargeting {
226
+ [rule: string]: unknown;
227
+ }
228
+
229
+ export interface LinkCreateOptions {
230
+ /** One channel, e.g. "email". */
231
+ channel?: string;
232
+ /** Several channels, e.g. ["email", "x"]. */
233
+ channels?: string[];
234
+ /** Let TrackRev pick the channel per click. */
235
+ smart?: boolean;
236
+ campaign?: string;
237
+ slug?: string;
238
+ tags?: string[];
239
+ targeting?: LinkTargeting;
240
+ expiresAt?: Timestamp;
241
+ maxClicks?: number;
242
+ expiredRedirectUrl?: string;
243
+ password?: string;
244
+ retargeting?: boolean;
245
+ folderId?: string;
246
+ external?: boolean;
247
+ }
248
+
249
+ export interface LinkUpdateOptions {
250
+ slug?: string;
251
+ utmCampaign?: string;
252
+ utmTerm?: string;
253
+ utmContent?: string;
254
+ targeting?: LinkTargeting;
255
+ expiresAt?: Timestamp;
256
+ maxClicks?: number;
257
+ expiredRedirectUrl?: string;
258
+ password?: string;
259
+ retargeting?: boolean;
260
+ }
261
+
262
+ /** One row for `createMany`. */
263
+ export interface LinkBulkRow {
264
+ url: string;
265
+ name?: string;
266
+ channel?: string;
267
+ [field: string]: unknown;
268
+ }
269
+
270
+ export interface LinksResource {
271
+ /** Performance per link for a window. */
272
+ list(options?: WindowOptions & {
273
+ limit?: number;
274
+ /** Attach each link's own record (expiry, password…). */
275
+ withSettings?: boolean;
276
+ }): Promise<ApiResult>;
277
+ /** The links themselves, newest first, with no window. */
278
+ records(options?: PageOptions & {
279
+ channel?: string;
280
+ destinationId?: string;
281
+ /** Search text. */
282
+ q?: string;
283
+ }): Promise<ApiResult>;
284
+ /** By id, slug or short code. */
285
+ get(idOrSlug: string): Promise<ApiResult>;
286
+ /** Create a campaign: one destination plus a link per channel. */
287
+ create(url: string, name: string, options?: LinkCreateOptions): Promise<ApiResult>;
288
+ /** Only the fields you pass change. */
289
+ update(id: string, options?: LinkUpdateOptions): Promise<ApiResult>;
290
+ /** The campaign and its other channels stay. */
291
+ remove(id: string): Promise<ApiResult>;
292
+ /** Up to 500 links in one call. A bad row is reported in `rows`, not thrown. */
293
+ createMany(rows: LinkBulkRow[]): Promise<ApiResult>;
294
+ /** The QR code as SVG text, not JSON. */
295
+ qr(idOrSlug: string, options?: { size?: number }): Promise<string>;
296
+ }
297
+
298
+ /* ── orders ───────────────────────────────────────────────────────────────── */
299
+
300
+ export interface OrdersResource {
301
+ /** Synced purchases, newest first. On a free workspace `amount` is null. */
302
+ list(options?: PageOptions & {
303
+ status?: string;
304
+ email?: string;
305
+ }): Promise<ApiResult>;
306
+ }
307
+
308
+ /* ── partners ─────────────────────────────────────────────────────────────── */
309
+
310
+ export interface PartnersResource {
311
+ /** Affiliates across every program, or one program's. */
312
+ list(options?: { programId?: string; status?: PartnerStatus }): Promise<ApiResult>;
313
+ /** Unlike the dashboard this sends no email, so re-running it mails nobody twice. */
314
+ setStatus(programId: string, partnerId: string, status: PartnerStatus): Promise<ApiResult>;
315
+ /** Pass null as `groupId` to drop them back to the program's own terms. */
316
+ setGroup(programId: string, partnerId: string, groupId: string | null): Promise<ApiResult>;
317
+ }
318
+
319
+ /* ── payouts ──────────────────────────────────────────────────────────────── */
320
+
321
+ export interface PayoutsResource {
322
+ /** Payout batches with open and all-time totals. */
323
+ list(options?: { status?: string; limit?: number }): Promise<ApiResult>;
324
+ /** Settle a batch you paid off-platform. Creating a batch stays dashboard-only. */
325
+ settle(id: string | number, options?: {
326
+ /** The rail's own id — a PayPal batch, a Wise transfer. */
327
+ reference?: string;
328
+ }): Promise<ApiResult>;
329
+ }
330
+
331
+ /* ── programs ─────────────────────────────────────────────────────────────── */
332
+
333
+ export interface ProgramsResource {
334
+ list(options?: { includeArchived?: boolean }): Promise<ApiResult>;
335
+ get(id: string): Promise<ApiResult>;
336
+ /** Only the fields you pass change: an omitted field must never reset a rate. */
337
+ update(
338
+ id: string,
339
+ options?: {
340
+ name?: string;
341
+ landingUrl?: string;
342
+ commissionType?: CommissionType;
343
+ /** A 0–1 fraction for percent programs, so 0.3 means 30%. Dollars for flat. */
344
+ commissionRate?: number;
345
+ recurringMonths?: number;
346
+ cookieWindowDays?: number;
347
+ minPayout?: number;
348
+ autoApprove?: boolean;
349
+ status?: ProgramStatus;
350
+ },
351
+ ): Promise<ApiResult>;
352
+ /** The program's affiliate tiers, each with the terms an affiliate in it really gets. */
353
+ groups(id: string): Promise<ApiResult>;
354
+ }
355
+
356
+ /* ── referrals ────────────────────────────────────────────────────────────── */
357
+
358
+ export interface ReferralsResource {
359
+ /** A user opts into your referral program. */
360
+ enroll(
361
+ externalUserId: string,
362
+ email: string,
363
+ tier: ReferrerTier,
364
+ options?: { name?: string; programId?: string },
365
+ ): Promise<ApiResult>;
366
+ /** A new user signed up. Pass one of `refCode`, `vid` or `referrerExternalUserId`. */
367
+ reportSignup(
368
+ newUserExternalUserId: string,
369
+ options?: {
370
+ refCode?: string;
371
+ vid?: string;
372
+ referrerExternalUserId?: string;
373
+ email?: string;
374
+ },
375
+ ): Promise<ApiResult>;
376
+ /** A user paid. Needs a secret key. Idempotent on your `orderId`. */
377
+ reportPurchase(
378
+ externalUserId: string,
379
+ orderId: string,
380
+ /** Major units, e.g. 49.99. */
381
+ amount: number,
382
+ options?: {
383
+ /** Default "usd". */
384
+ currency?: string;
385
+ email?: string;
386
+ /** True for renewals. */
387
+ recurring?: boolean;
388
+ ts?: Timestamp;
389
+ },
390
+ ): Promise<ApiResult>;
391
+ /** A user's referral link, KPIs and earnings. */
392
+ stats(
393
+ externalUserId: string,
394
+ options?: {
395
+ email?: string;
396
+ tier?: ReferrerTier;
397
+ /** 7 to 90. */
398
+ days?: number;
399
+ },
400
+ ): Promise<ApiResult>;
401
+ /** Where an affiliate gets paid. PayPal only for now. */
402
+ setPayoutMethod(externalUserId: string, paypalEmail: string): Promise<ApiResult>;
403
+ /** Switch between earning credits ("referrer") and cash ("affiliate"). */
404
+ setRewardMode(externalUserId: string, mode: RewardMode): Promise<ApiResult>;
405
+ }
406
+
407
+ /* ── retargeting ──────────────────────────────────────────────────────────── */
408
+
409
+ export interface RetargetingResource {
410
+ /** Your ad-pixel library, plus the id shape each provider expects. */
411
+ list(): Promise<ApiResult>;
412
+ /** e.g. set("meta", "1234567890"). The id must match that provider's shape. */
413
+ set(provider: string, pixelId: string): Promise<ApiResult>;
414
+ remove(provider: string): Promise<ApiResult>;
415
+ }
416
+
417
+ /* ── revenue ──────────────────────────────────────────────────────────────── */
418
+
419
+ export interface RevenueResource {
420
+ /** Connected billing providers. Credentials are never returned. */
421
+ connections(): Promise<ApiResult>;
422
+ connection(id: string): Promise<ApiResult>;
423
+ /** What can be connected, and which credential fields each one needs. */
424
+ providers(): Promise<ApiResult>;
425
+ /** Proved with one live read before anything is stored, so a bad key fails here. */
426
+ connect(
427
+ provider: string,
428
+ credentials: Record<string, string>,
429
+ options?: { sandbox?: boolean },
430
+ ): Promise<ApiResult>;
431
+ /** With it set, sales arrive in seconds; without it the connection is cron-only. */
432
+ setWebhookSecret(id: string, webhookSecret: string | null): Promise<ApiResult>;
433
+ /** Past orders are kept. */
434
+ disconnect(id: string): Promise<ApiResult>;
435
+ /** Omit `connectionId` to sync every connection plus Stripe. */
436
+ sync(options?: { connectionId?: string }): Promise<ApiResult>;
437
+ }
438
+
439
+ /* ── settings ─────────────────────────────────────────────────────────────── */
440
+
441
+ export interface SettingsResource {
442
+ /** Every transactional email, with whether it is on for this workspace. */
443
+ notifications(): Promise<ApiResult>;
444
+ /** e.g. setNotification("sale.created", false). */
445
+ setNotification(key: string, enabled: boolean): Promise<ApiResult>;
446
+ /** The white-label settings affiliates see. */
447
+ branding(): Promise<ApiResult>;
448
+ /** Only the fields you pass change. */
449
+ updateBranding(options?: { color?: string; logoUrl?: string }): Promise<ApiResult>;
450
+ }
451
+
452
+ /* ── visitors ─────────────────────────────────────────────────────────────── */
453
+
454
+ export interface VisitorsResource {
455
+ /** Visitors, most recently seen first. */
456
+ list(options?: PageOptions & { email?: string }): Promise<ApiResult>;
457
+ get(id: string): Promise<ApiResult>;
458
+ /** Every click, identify event and order for one visitor, oldest first. */
459
+ journey(id: string): Promise<ApiResult>;
460
+ }
461
+
462
+ /* ── webhooks ─────────────────────────────────────────────────────────────── */
463
+
464
+ export interface WebhooksResource {
465
+ /** The signing secret is never included here. */
466
+ list(): Promise<ApiResult>;
467
+ /** The catalogue of events an endpoint can subscribe to. */
468
+ events(): Promise<ApiResult>;
469
+ get(id: string): Promise<ApiResult>;
470
+ /** `url` must be https. The response carries the signing secret ONCE. */
471
+ create(url: string, events: string[]): Promise<ApiResult>;
472
+ /** Only the fields you pass change. Pause it with `active: false`. */
473
+ update(
474
+ id: string,
475
+ options?: { url?: string; events?: string[]; active?: boolean },
476
+ ): Promise<ApiResult>;
477
+ /** Deliveries stop at once. */
478
+ remove(id: string): Promise<ApiResult>;
479
+ }
480
+
481
+ /* ── The client ───────────────────────────────────────────────────────────── */
482
+
483
+ /**
484
+ * The TrackRev API client.
485
+ *
486
+ * import { TrackRev } from "trackrev";
487
+ *
488
+ * const trackrev = new TrackRev(process.env.TRACKREV_KEY);
489
+ * const { channels } = await trackrev.channels.list({ days: 7 });
490
+ *
491
+ * Every method rejects with a TrackRevError when the API says no.
492
+ */
493
+ export class TrackRev {
494
+ constructor(key: string, options?: TrackRevOptions);
495
+
496
+ key: string;
497
+ apiUrl: string;
498
+ timeoutMs: number;
499
+ maxRetries: number;
500
+
501
+ /** Who am I, and what can this key do. */
502
+ me(): Promise<ApiResult>;
503
+
504
+ /**
505
+ * The one way every resource reaches the API. Call it directly for an
506
+ * endpoint the SDK has no method for yet.
507
+ */
508
+ request(
509
+ method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE",
510
+ path: string,
511
+ options?: { body?: unknown },
512
+ ): Promise<any>;
513
+
514
+ attribution: AttributionResource;
515
+ channels: ChannelsResource;
516
+ clicks: ClicksResource;
517
+ commissions: CommissionsResource;
518
+ credits: CreditsResource;
519
+ domains: DomainsResource;
520
+ export: ExportResource;
521
+ folders: FoldersResource;
522
+ keys: KeysResource;
523
+ links: LinksResource;
524
+ orders: OrdersResource;
525
+ partners: PartnersResource;
526
+ payouts: PayoutsResource;
527
+ programs: ProgramsResource;
528
+ referrals: ReferralsResource;
529
+ retargeting: RetargetingResource;
530
+ revenue: RevenueResource;
531
+ settings: SettingsResource;
532
+ visitors: VisitorsResource;
533
+ webhooks: WebhooksResource;
534
+ }
@@ -0,0 +1 @@
1
+ export { TrackRev, TrackRevError, TrackRevConnectionError, VERSION } from "./client.js";
@@ -0,0 +1,20 @@
1
+ export function attribution(request) {
2
+ return {
3
+ // The workspace's attribution model and lookback window, plus the
4
+ // catalogue of models, so a client can offer the choice without
5
+ // hardcoding the list.
6
+ get: () => {
7
+ return request("GET", "/attribution");
8
+ },
9
+
10
+ // Change the model or the window. Both retroactively change every
11
+ // revenue figure the product reports, because the engine replays
12
+ // each journey against whatever is set here. windowDays is clamped
13
+ // to 1–365.
14
+ update: ({ model, windowDays } = {}) => {
15
+ return request("PATCH", "/attribution", {
16
+ body: { model, window_days: windowDays },
17
+ });
18
+ },
19
+ };
20
+ }
@@ -0,0 +1,16 @@
1
+ export function channels(request) {
2
+ return {
3
+ // Performance per traffic source, ranked by revenue. Window: days
4
+ // (default 30) or from/to as YYYY-MM-DD. ltv adds all-time lifetime
5
+ // value per channel.
6
+ list: ({ days, from, to, ltv } = {}) => {
7
+ const params = new URLSearchParams();
8
+ if (days) params.set("days", String(days));
9
+ if (from) params.set("from", from);
10
+ if (to) params.set("to", to);
11
+ if (ltv) params.set("ltv", "1");
12
+ const qs = params.toString();
13
+ return request("GET", qs ? `/channels?${qs}` : "/channels");
14
+ },
15
+ };
16
+ }
@@ -0,0 +1,16 @@
1
+ export function clicks(request) {
2
+ return {
3
+ // The raw click stream, newest first. To page, pass the previous
4
+ // call's next_cursor as before; null means you reached the end.
5
+ // Bot clicks are excluded unless you ask for them.
6
+ list: ({ limit, before, linkId, includeBots } = {}) => {
7
+ const params = new URLSearchParams();
8
+ if (limit) params.set("limit", String(limit));
9
+ if (before) params.set("before", before);
10
+ if (linkId) params.set("link_id", linkId);
11
+ if (includeBots) params.set("bots", "include");
12
+ const qs = params.toString();
13
+ return request("GET", qs ? `/clicks?${qs}` : "/clicks");
14
+ },
15
+ };
16
+ }
@@ -0,0 +1,40 @@
1
+ export function commissions(request) {
2
+ return {
3
+ // The commission ledger, newest first. chain_level is 1 for the
4
+ // affiliate who sold and 2 or more for an upline earning from them.
5
+ list: ({ limit, cursor, status, partnerId } = {}) => {
6
+ const params = new URLSearchParams();
7
+ if (limit) params.set("limit", String(limit));
8
+ if (cursor) params.set("cursor", cursor);
9
+ if (status) params.set("status", status);
10
+ if (partnerId) params.set("partner_id", partnerId);
11
+ const qs = params.toString();
12
+ return request("GET", qs ? `/commissions?${qs}` : "/commissions");
13
+ },
14
+
15
+ // Record an off-platform deal by hand. earnings is what the partner
16
+ // takes home and is required, because a manual commission exists
17
+ // precisely when the program's normal rate did not apply.
18
+ create: (programId, partnerId, amount, earnings, { currency, notes } = {}) => {
19
+ return request("POST", "/commissions", {
20
+ body: {
21
+ program_id: programId,
22
+ partner_id: partnerId,
23
+ amount,
24
+ earnings,
25
+ currency,
26
+ notes,
27
+ },
28
+ });
29
+ },
30
+
31
+ // Usually voiding one entered in error. Refused once the commission
32
+ // sits in a payout batch, where voiding it would leave the batch
33
+ // total disagreeing with its rows.
34
+ setStatus: (id, status) => {
35
+ return request("PATCH", `/commissions/${encodeURIComponent(id)}`, {
36
+ body: { status },
37
+ });
38
+ },
39
+ };
40
+ }
@@ -0,0 +1,23 @@
1
+ export function credits(request) {
2
+ return {
3
+ // Credit grants plus a balance summary. Pass partnerId or
4
+ // externalUserId — one of the two is required. status: "earned",
5
+ // "delivered" or "all" (default all).
6
+ list: ({ partnerId, externalUserId, status, limit } = {}) => {
7
+ const params = new URLSearchParams();
8
+ if (partnerId) params.set("partner_id", partnerId);
9
+ if (externalUserId) params.set("external_user_id", externalUserId);
10
+ if (status) params.set("status", status);
11
+ if (limit) params.set("limit", String(limit));
12
+ const qs = params.toString();
13
+ return request("GET", qs ? `/credits?${qs}` : "/credits");
14
+ },
15
+
16
+ // Confirm a credit was actually applied in your product: it moves
17
+ // from earned to delivered and fires credit.delivered. Calling it on
18
+ // an already-delivered credit succeeds and changes nothing.
19
+ markDelivered: (id) => {
20
+ return request("POST", `/credits/${encodeURIComponent(id)}/mark-delivered`);
21
+ },
22
+ };
23
+ }