@itm-studio/partner-sdk 0.2.1 → 0.2.3
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/README.md +341 -0
- package/dist/index.d.mts +161 -2
- package/dist/index.d.ts +161 -2
- package/dist/index.js +254 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +254 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/schema/partner.graphql +128 -0
package/README.md
CHANGED
|
@@ -64,6 +64,31 @@ Get your partner API token from the ITM backstage dashboard: **Settings > Partne
|
|
|
64
64
|
|
|
65
65
|
The token is sent as the `x-partner-api-key` header on every request. Your brand is determined automatically from the token — no need to pass brand IDs.
|
|
66
66
|
|
|
67
|
+
Keep the partner token on your server. Do not expose it from browser code or client-side mobile code.
|
|
68
|
+
|
|
69
|
+
For request-scoped mutations such as partner brand subscriptions, create the client inside the incoming request and forward `x-forwarded-for` and `user-agent` so the backend can enrich compliance metadata when those fields are omitted from `input.compliance`.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { createITMPartnerClient } from '@itm-studio/partner-sdk';
|
|
73
|
+
|
|
74
|
+
export function createITMClientForRequest(request: Request) {
|
|
75
|
+
return createITMPartnerClient({
|
|
76
|
+
token: process.env.ITM_PARTNER_TOKEN!,
|
|
77
|
+
headers: () => {
|
|
78
|
+
const forwardedFor = request.headers.get('x-forwarded-for');
|
|
79
|
+
const userAgent = request.headers.get('user-agent');
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
...(forwardedFor ? { 'x-forwarded-for': forwardedFor } : {}),
|
|
83
|
+
...(userAgent ? { 'user-agent': userAgent } : {}),
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If you also send `input.compliance`, the backend keeps the values you provide and backfills missing `ipAddress` and `userAgent` from the forwarded headers when available.
|
|
91
|
+
|
|
67
92
|
## Available Queries
|
|
68
93
|
|
|
69
94
|
### `getPartnerMomentsForBrand`
|
|
@@ -114,6 +139,29 @@ const { getPartnerMoment } = await itm.query({
|
|
|
114
139
|
});
|
|
115
140
|
```
|
|
116
141
|
|
|
142
|
+
### `getMomentStats`
|
|
143
|
+
|
|
144
|
+
Get cached partner-facing counts for a moment owned by the authenticated partner's brand.
|
|
145
|
+
|
|
146
|
+
- `ticketsCount` counts confirmed tickets only.
|
|
147
|
+
- `waitlistCount` counts active waitlist entries.
|
|
148
|
+
- `externalRsvpCount` counts external RSVPs.
|
|
149
|
+
- `ticketRsvpRequestsCount` counts ticket RSVP requests.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const { getMomentStats } = await itm.query({
|
|
153
|
+
getMomentStats: {
|
|
154
|
+
__args: { momentSlug: 'my-event-slug' },
|
|
155
|
+
ticketsCount: true,
|
|
156
|
+
waitlistCount: true,
|
|
157
|
+
externalRsvpCount: true,
|
|
158
|
+
ticketRsvpRequestsCount: true,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
> **Note:** `getMomentStats` returns `null` if the moment does not exist or is not owned by the authenticated partner's brand.
|
|
164
|
+
|
|
117
165
|
### `getPartnerTicketsForMoment`
|
|
118
166
|
|
|
119
167
|
Get paginated tickets for a moment.
|
|
@@ -295,6 +343,299 @@ const { getPartnerPublicEchoes } = await itm.query({
|
|
|
295
343
|
|
|
296
344
|
The SDK supports write operations via `client.mutation()`. All mutations use the same authentication — your brand is determined from the token.
|
|
297
345
|
|
|
346
|
+
## Partner Brand Subscription Guide
|
|
347
|
+
|
|
348
|
+
The partner brand subscription API supports two integration modes:
|
|
349
|
+
|
|
350
|
+
- Direct subscribe: create the subscription immediately in one mutation.
|
|
351
|
+
- OTP subscribe: send an SMS code first, then confirm with a second mutation.
|
|
352
|
+
|
|
353
|
+
Use direct subscribe when your product already has the right consent flow and you do not need to prove possession of the phone number in real time.
|
|
354
|
+
|
|
355
|
+
Use OTP subscribe when you want the user to confirm the phone number before the brand subscription is created.
|
|
356
|
+
|
|
357
|
+
### Flow Summary
|
|
358
|
+
|
|
359
|
+
| Mode | First mutation | First response | Second mutation |
|
|
360
|
+
|---|---|---|---|
|
|
361
|
+
| Direct | `createPartnerBrandSubscription` with `requireOtpVerification: false` or omitted | `verificationRequired: false` and `subscription` populated | None |
|
|
362
|
+
| OTP | `createPartnerBrandSubscription` with `requireOtpVerification: true` | `verificationRequired: true`, `verificationToken`, `subscription: null` | `verifyPartnerBrandSubscription` |
|
|
363
|
+
|
|
364
|
+
### Input Behavior
|
|
365
|
+
|
|
366
|
+
- `phoneNumber`: send an E.164 phone number such as `+14155551234`.
|
|
367
|
+
- `fullName`: optional, but if you send it, include both first and last name.
|
|
368
|
+
- `email`: optional and attached to the subscribed user if provided.
|
|
369
|
+
- `listNames`: optional brand list names. Missing lists are created automatically and the subscribed user is attached to them.
|
|
370
|
+
- `compliance`: optional metadata about how consent was collected. This is the right place for fields like `pageUrl`, `submissionMethod`, `submittedAt`, `timezone`, and geo/browser/device details.
|
|
371
|
+
- `compliance.ipAddress` and `compliance.userAgent`: optional. If you omit them and forward `x-forwarded-for` and `user-agent`, the backend backfills those values for you.
|
|
372
|
+
- `postSubscriptionMessage`: optional welcome message delivered automatically after the subscription becomes active. See [Post-Subscription Welcome Message](#post-subscription-welcome-message).
|
|
373
|
+
|
|
374
|
+
### OTP Flow Step By Step
|
|
375
|
+
|
|
376
|
+
1. Call `createPartnerBrandSubscription` with `requireOtpVerification: true`.
|
|
377
|
+
2. Store the returned `verificationToken` in the user session or another short-lived server-side state container associated with the current signup attempt.
|
|
378
|
+
3. Collect the SMS code from the user.
|
|
379
|
+
4. Call `verifyPartnerBrandSubscription` with that `verificationToken` and `code`.
|
|
380
|
+
|
|
381
|
+
`verificationToken` is brand-scoped. A token created under one partner token cannot be verified by another brand's partner token.
|
|
382
|
+
|
|
383
|
+
If the verification token is invalid or expired, verification fails and the subscription is not created.
|
|
384
|
+
|
|
385
|
+
### Post-Subscription Welcome Message
|
|
386
|
+
|
|
387
|
+
`postSubscriptionMessage` lets you fan out a welcome touch across SMS, email, and push the moment a subscription becomes active. The backend dispatches each channel asynchronously after the subscription is created (direct mode) or verified (OTP mode), so the mutation still returns synchronously — delivery happens in the background.
|
|
388
|
+
|
|
389
|
+
**Channels are independent.** Provide any combination of `sms`, `email`, and `push`. Channels you omit are skipped.
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
await itm.mutation({
|
|
393
|
+
createPartnerBrandSubscription: {
|
|
394
|
+
__args: {
|
|
395
|
+
input: {
|
|
396
|
+
phoneNumber: '+14155550111',
|
|
397
|
+
fullName: 'Jane Doe',
|
|
398
|
+
email: 'jane@example.com',
|
|
399
|
+
postSubscriptionMessage: {
|
|
400
|
+
sms: {
|
|
401
|
+
body: 'Welcome to Acme — your first drop ships Friday. Reply STOP to opt out.',
|
|
402
|
+
mediaUrls: ['https://cdn.example.com/welcome-banner.png'],
|
|
403
|
+
},
|
|
404
|
+
email: {
|
|
405
|
+
subject: 'Welcome to Acme',
|
|
406
|
+
body: 'Hi Jane,\n\nThanks for subscribing — here is what to expect next...',
|
|
407
|
+
},
|
|
408
|
+
push: {
|
|
409
|
+
title: 'Welcome to Acme',
|
|
410
|
+
body: 'Tap to see what is dropping this week.',
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
verificationRequired: true,
|
|
416
|
+
subscription: { uid: true },
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Channel inputs:**
|
|
422
|
+
|
|
423
|
+
| Channel | Required | Optional | Notes |
|
|
424
|
+
|---|---|---|---|
|
|
425
|
+
| `sms` | `body` | `mediaUrls` (string array of image URLs for MMS) | Delivered to `phoneNumber`. |
|
|
426
|
+
| `email` | `subject`, `body` | — | `body` is plain text or markdown, rendered via React Email. Skipped if the user has no primary email or the brand has no configured email alias. |
|
|
427
|
+
| `push` | `title`, `body` | — | Skipped if the user has no push tokens or has opted out of brand messages. |
|
|
428
|
+
|
|
429
|
+
**Delivery semantics:**
|
|
430
|
+
|
|
431
|
+
- The message is sent **at most once per active subscription period**. The backend uses an atomic per-channel claim plus an idempotency key on each underlying task, so retrying the mutation (for example after a transient network failure) will not duplicate sends.
|
|
432
|
+
- The message is delivered when the subscription is **newly created or reactivated** — re-subscribing an already-active user is a no-op.
|
|
433
|
+
- In OTP mode, the message fires **after** `verifyPartnerBrandSubscription` succeeds, not when the OTP is requested.
|
|
434
|
+
- Channel failures are isolated: if email cannot be sent because the user has no primary email, SMS and push are still attempted.
|
|
435
|
+
|
|
436
|
+
**Recommended usage:**
|
|
437
|
+
|
|
438
|
+
- Pass `postSubscriptionMessage` on the **first** `createPartnerBrandSubscription` call. In OTP mode, the message is buffered with the pending session and delivered after `verifyPartnerBrandSubscription`. You do **not** repeat it on the verify call.
|
|
439
|
+
- For a marketing-style first SMS, prefer including a clear opt-out instruction (e.g. `Reply STOP to opt out`) alongside any branded copy.
|
|
440
|
+
- For the email channel, your brand must have an email alias configured on the backend. Confirm this in backstage before relying on the email channel in production.
|
|
441
|
+
|
|
442
|
+
### `createPartnerBrandSubscription`
|
|
443
|
+
|
|
444
|
+
Subscribe a phone number to the authenticated partner brand.
|
|
445
|
+
|
|
446
|
+
- Omit `requireOtpVerification` or set it to `false` to create the subscription immediately.
|
|
447
|
+
- Set `requireOtpVerification: true` to start the OTP flow. The backend sends the code to the provided phone number and returns a `verificationToken`.
|
|
448
|
+
- If you pass `fullName`, include both first and last name.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
const { createPartnerBrandSubscription } = await itm.mutation({
|
|
452
|
+
createPartnerBrandSubscription: {
|
|
453
|
+
__args: {
|
|
454
|
+
input: {
|
|
455
|
+
phoneNumber: '+14155550111',
|
|
456
|
+
fullName: 'Jane Doe',
|
|
457
|
+
email: 'jane@example.com',
|
|
458
|
+
listNames: ['VIP', 'Newsletter'],
|
|
459
|
+
compliance: {
|
|
460
|
+
pageUrl: 'https://example.com/signup',
|
|
461
|
+
submissionMethod: 'partner_sdk',
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
verificationRequired: true,
|
|
466
|
+
verificationToken: true,
|
|
467
|
+
subscription: {
|
|
468
|
+
uid: true,
|
|
469
|
+
isActive: true,
|
|
470
|
+
subscribedAt: true,
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
if (!createPartnerBrandSubscription.verificationRequired) {
|
|
476
|
+
console.log(createPartnerBrandSubscription.subscription?.uid);
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
When `verificationRequired` is `false`, `subscription` is populated and `verificationToken` is `null`.
|
|
481
|
+
|
|
482
|
+
This is the recommended mode when:
|
|
483
|
+
|
|
484
|
+
- You are subscribing from an already-authenticated server flow.
|
|
485
|
+
- You already have consent and do not need phone possession verification.
|
|
486
|
+
- You want a single network round trip.
|
|
487
|
+
|
|
488
|
+
### `verifyPartnerBrandSubscription`
|
|
489
|
+
|
|
490
|
+
Complete a subscription created with `requireOtpVerification: true`.
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
const { createPartnerBrandSubscription } = await itm.mutation({
|
|
494
|
+
createPartnerBrandSubscription: {
|
|
495
|
+
__args: {
|
|
496
|
+
input: {
|
|
497
|
+
phoneNumber: '+14155550112',
|
|
498
|
+
requireOtpVerification: true,
|
|
499
|
+
fullName: 'Otp User',
|
|
500
|
+
compliance: {
|
|
501
|
+
pageUrl: 'https://example.com/otp-signup',
|
|
502
|
+
submissionMethod: 'partner_sdk',
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
verificationRequired: true,
|
|
507
|
+
verificationToken: true,
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
if (!createPartnerBrandSubscription.verificationToken) {
|
|
512
|
+
throw new Error('Expected OTP verification to be required');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Collect the SMS code from the user in your UI or API flow.
|
|
516
|
+
const code = '123456';
|
|
517
|
+
|
|
518
|
+
const { verifyPartnerBrandSubscription } = await itm.mutation({
|
|
519
|
+
verifyPartnerBrandSubscription: {
|
|
520
|
+
__args: {
|
|
521
|
+
input: {
|
|
522
|
+
verificationToken:
|
|
523
|
+
createPartnerBrandSubscription.verificationToken,
|
|
524
|
+
code,
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
uid: true,
|
|
528
|
+
isActive: true,
|
|
529
|
+
subscribedAt: true,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
console.log(verifyPartnerBrandSubscription.uid);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
When OTP is required, `createPartnerBrandSubscription` returns `verificationRequired: true`, `subscription: null`, and a non-null `verificationToken`. Pass that token into `verifyPartnerBrandSubscription` together with the one-time code sent to the phone number.
|
|
537
|
+
|
|
538
|
+
This is the recommended mode when:
|
|
539
|
+
|
|
540
|
+
- The subscription starts from a public signup form.
|
|
541
|
+
- You want to prove the user controls the submitted phone number.
|
|
542
|
+
- Your compliance flow requires explicit OTP confirmation before the subscription is created.
|
|
543
|
+
|
|
544
|
+
### Full OTP Example
|
|
545
|
+
|
|
546
|
+
This is the full two-step flow most integrators will want to implement from a server route or server action.
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
import { createITMPartnerClient } from '@itm-studio/partner-sdk';
|
|
550
|
+
|
|
551
|
+
function createRequestScopedITM(request: Request) {
|
|
552
|
+
return createITMPartnerClient({
|
|
553
|
+
token: process.env.ITM_PARTNER_TOKEN!,
|
|
554
|
+
headers: () => ({
|
|
555
|
+
...(request.headers.get('x-forwarded-for')
|
|
556
|
+
? { 'x-forwarded-for': request.headers.get('x-forwarded-for')! }
|
|
557
|
+
: {}),
|
|
558
|
+
...(request.headers.get('user-agent')
|
|
559
|
+
? { 'user-agent': request.headers.get('user-agent')! }
|
|
560
|
+
: {}),
|
|
561
|
+
}),
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export async function startOtpSubscription(request: Request) {
|
|
566
|
+
const itm = createRequestScopedITM(request);
|
|
567
|
+
|
|
568
|
+
const { createPartnerBrandSubscription } = await itm.mutation({
|
|
569
|
+
createPartnerBrandSubscription: {
|
|
570
|
+
__args: {
|
|
571
|
+
input: {
|
|
572
|
+
phoneNumber: '+14155550112',
|
|
573
|
+
requireOtpVerification: true,
|
|
574
|
+
fullName: 'Otp User',
|
|
575
|
+
email: 'otp@example.com',
|
|
576
|
+
listNames: ['Members', 'SMS'],
|
|
577
|
+
compliance: {
|
|
578
|
+
pageUrl: 'https://example.com/join',
|
|
579
|
+
submissionMethod: 'partner_sdk',
|
|
580
|
+
submittedAt: new Date().toISOString(),
|
|
581
|
+
timezone: 'America/New_York',
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
verificationRequired: true,
|
|
586
|
+
verificationToken: true,
|
|
587
|
+
subscription: {
|
|
588
|
+
uid: true,
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
if (!createPartnerBrandSubscription.verificationRequired) {
|
|
594
|
+
return {
|
|
595
|
+
status: 'subscribed',
|
|
596
|
+
subscriptionUid: createPartnerBrandSubscription.subscription?.uid ?? null,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
status: 'otp_required',
|
|
602
|
+
verificationToken: createPartnerBrandSubscription.verificationToken,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export async function finishOtpSubscription(
|
|
607
|
+
request: Request,
|
|
608
|
+
verificationToken: string,
|
|
609
|
+
code: string,
|
|
610
|
+
) {
|
|
611
|
+
const itm = createRequestScopedITM(request);
|
|
612
|
+
|
|
613
|
+
const { verifyPartnerBrandSubscription } = await itm.mutation({
|
|
614
|
+
verifyPartnerBrandSubscription: {
|
|
615
|
+
__args: {
|
|
616
|
+
input: {
|
|
617
|
+
verificationToken,
|
|
618
|
+
code,
|
|
619
|
+
},
|
|
620
|
+
},
|
|
621
|
+
uid: true,
|
|
622
|
+
isActive: true,
|
|
623
|
+
subscribedAt: true,
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
return verifyPartnerBrandSubscription;
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Common Integration Notes
|
|
632
|
+
|
|
633
|
+
- Create the ITM client inside the incoming request when you need compliance backfill from headers.
|
|
634
|
+
- Persist the OTP `verificationToken` only for the duration of the signup flow. Treat it as short-lived state, not a durable identifier.
|
|
635
|
+
- Do not attempt to verify an OTP token with a different partner token than the one that created it.
|
|
636
|
+
- If you are building a browser form, post to your own backend first, then have your backend call the ITM Partner SDK. Do not call the SDK directly from the browser.
|
|
637
|
+
- If you need to associate the user with CRM-style segments on subscribe, send `listNames` during the initial create call. Those lists are created on demand.
|
|
638
|
+
|
|
298
639
|
### Media Upload Flow
|
|
299
640
|
|
|
300
641
|
Uploading media (e.g. cover images) is a two-step process:
|
package/dist/index.d.mts
CHANGED
|
@@ -162,6 +162,13 @@ interface PartnerCustomer {
|
|
|
162
162
|
tickets: Ticket[];
|
|
163
163
|
__typename: 'PartnerCustomer';
|
|
164
164
|
}
|
|
165
|
+
interface PartnerMomentStats {
|
|
166
|
+
ticketsCount: Scalars['Int'];
|
|
167
|
+
waitlistCount: Scalars['Int'];
|
|
168
|
+
externalRsvpCount: Scalars['Int'];
|
|
169
|
+
ticketRsvpRequestsCount: Scalars['Int'];
|
|
170
|
+
__typename: 'PartnerMomentStats';
|
|
171
|
+
}
|
|
165
172
|
interface MomentCollectionLink {
|
|
166
173
|
uid: Scalars['ID'];
|
|
167
174
|
url: Scalars['String'];
|
|
@@ -260,11 +267,24 @@ interface GetBrandEchoesForUserResponse {
|
|
|
260
267
|
nextCursor: (Scalars['String'] | null);
|
|
261
268
|
__typename: 'GetBrandEchoesForUserResponse';
|
|
262
269
|
}
|
|
270
|
+
interface BrandSubscription {
|
|
271
|
+
uid: Scalars['ID'];
|
|
272
|
+
isActive: Scalars['Boolean'];
|
|
273
|
+
subscribedAt: Scalars['DateTime'];
|
|
274
|
+
createdAt: Scalars['DateTime'];
|
|
275
|
+
updatedAt: Scalars['DateTime'];
|
|
276
|
+
__typename: 'BrandSubscription';
|
|
277
|
+
}
|
|
263
278
|
interface Query {
|
|
264
279
|
/** Get paginated moments for the brand associated with the partner token. */
|
|
265
280
|
getPartnerMomentsForBrand: GetPublicMomentsResponse;
|
|
266
281
|
/** Get a single moment by slug. */
|
|
267
282
|
getPartnerMoment: (Moment | null);
|
|
283
|
+
/**
|
|
284
|
+
* Get cached partner-facing counts for a moment.
|
|
285
|
+
* Only returns stats for moments owned by the authenticated partner's brand.
|
|
286
|
+
*/
|
|
287
|
+
getPartnerMomentStats: (PartnerMomentStats | null);
|
|
268
288
|
/** Get paginated tickets for a moment. */
|
|
269
289
|
getPartnerTicketsForMoment: GetTicketsResponse;
|
|
270
290
|
/**
|
|
@@ -315,6 +335,12 @@ interface MediaAsset {
|
|
|
315
335
|
updatedAt: Scalars['DateTime'];
|
|
316
336
|
__typename: 'MediaAsset';
|
|
317
337
|
}
|
|
338
|
+
interface CreatePartnerBrandSubscriptionResponse {
|
|
339
|
+
subscription: (BrandSubscription | null);
|
|
340
|
+
verificationRequired: Scalars['Boolean'];
|
|
341
|
+
verificationToken: (Scalars['String'] | null);
|
|
342
|
+
__typename: 'CreatePartnerBrandSubscriptionResponse';
|
|
343
|
+
}
|
|
318
344
|
interface Mutation {
|
|
319
345
|
/**
|
|
320
346
|
* Get a presigned S3 URL for direct file upload.
|
|
@@ -326,11 +352,18 @@ interface Mutation {
|
|
|
326
352
|
* Call after uploading to S3 via the presigned URL from getPartnerUploadUrl.
|
|
327
353
|
*/
|
|
328
354
|
createPartnerMediaAsset: MediaAsset;
|
|
355
|
+
/**
|
|
356
|
+
* Subscribe a user to the authenticated partner brand.
|
|
357
|
+
* Set requireOtpVerification to true to start a two-step OTP flow.
|
|
358
|
+
*/
|
|
359
|
+
createPartnerBrandSubscription: CreatePartnerBrandSubscriptionResponse;
|
|
329
360
|
/**
|
|
330
361
|
* Create a moment with optional venue and ticket tiers in one atomic operation.
|
|
331
362
|
* When type is IRL, the venue field is required.
|
|
332
363
|
*/
|
|
333
364
|
createPartnerMoment: Moment;
|
|
365
|
+
/** Complete a partner brand subscription that was created with requireOtpVerification=true. */
|
|
366
|
+
verifyPartnerBrandSubscription: BrandSubscription;
|
|
334
367
|
__typename: 'Mutation';
|
|
335
368
|
}
|
|
336
369
|
interface CurrencyGenqlSelection {
|
|
@@ -484,6 +517,14 @@ interface PartnerCustomerGenqlSelection {
|
|
|
484
517
|
__typename?: boolean | number;
|
|
485
518
|
__scalar?: boolean | number;
|
|
486
519
|
}
|
|
520
|
+
interface PartnerMomentStatsGenqlSelection {
|
|
521
|
+
ticketsCount?: boolean | number;
|
|
522
|
+
waitlistCount?: boolean | number;
|
|
523
|
+
externalRsvpCount?: boolean | number;
|
|
524
|
+
ticketRsvpRequestsCount?: boolean | number;
|
|
525
|
+
__typename?: boolean | number;
|
|
526
|
+
__scalar?: boolean | number;
|
|
527
|
+
}
|
|
487
528
|
interface MomentCollectionLinkGenqlSelection {
|
|
488
529
|
uid?: boolean | number;
|
|
489
530
|
url?: boolean | number;
|
|
@@ -595,6 +636,15 @@ interface GetBrandEchoesForUserResponseGenqlSelection {
|
|
|
595
636
|
__typename?: boolean | number;
|
|
596
637
|
__scalar?: boolean | number;
|
|
597
638
|
}
|
|
639
|
+
interface BrandSubscriptionGenqlSelection {
|
|
640
|
+
uid?: boolean | number;
|
|
641
|
+
isActive?: boolean | number;
|
|
642
|
+
subscribedAt?: boolean | number;
|
|
643
|
+
createdAt?: boolean | number;
|
|
644
|
+
updatedAt?: boolean | number;
|
|
645
|
+
__typename?: boolean | number;
|
|
646
|
+
__scalar?: boolean | number;
|
|
647
|
+
}
|
|
598
648
|
interface QueryGenqlSelection {
|
|
599
649
|
/** Get paginated moments for the brand associated with the partner token. */
|
|
600
650
|
getPartnerMomentsForBrand?: (GetPublicMomentsResponseGenqlSelection & {
|
|
@@ -613,6 +663,15 @@ interface QueryGenqlSelection {
|
|
|
613
663
|
slug: Scalars['String'];
|
|
614
664
|
};
|
|
615
665
|
});
|
|
666
|
+
/**
|
|
667
|
+
* Get cached partner-facing counts for a moment.
|
|
668
|
+
* Only returns stats for moments owned by the authenticated partner's brand.
|
|
669
|
+
*/
|
|
670
|
+
getPartnerMomentStats?: (PartnerMomentStatsGenqlSelection & {
|
|
671
|
+
__args: {
|
|
672
|
+
momentSlug: Scalars['String'];
|
|
673
|
+
};
|
|
674
|
+
});
|
|
616
675
|
/** Get paginated tickets for a moment. */
|
|
617
676
|
getPartnerTicketsForMoment?: (GetTicketsResponseGenqlSelection & {
|
|
618
677
|
__args: {
|
|
@@ -713,6 +772,79 @@ interface CreatePartnerMomentInput {
|
|
|
713
772
|
/** Ticket tiers to create along with the moment. */
|
|
714
773
|
ticketTiers?: (CreatePartnerTicketTierInput[] | null);
|
|
715
774
|
}
|
|
775
|
+
interface SubscriptionComplianceInput {
|
|
776
|
+
browserName?: (Scalars['String'] | null);
|
|
777
|
+
browserVersion?: (Scalars['String'] | null);
|
|
778
|
+
deviceType?: (Scalars['String'] | null);
|
|
779
|
+
geoAccuracy?: (Scalars['Float'] | null);
|
|
780
|
+
geoCity?: (Scalars['String'] | null);
|
|
781
|
+
geoCountry?: (Scalars['String'] | null);
|
|
782
|
+
geoLatitude?: (Scalars['Float'] | null);
|
|
783
|
+
geoLongitude?: (Scalars['Float'] | null);
|
|
784
|
+
geoRegion?: (Scalars['String'] | null);
|
|
785
|
+
ipAddress?: (Scalars['String'] | null);
|
|
786
|
+
language?: (Scalars['String'] | null);
|
|
787
|
+
osName?: (Scalars['String'] | null);
|
|
788
|
+
osVersion?: (Scalars['String'] | null);
|
|
789
|
+
pageUrl?: (Scalars['String'] | null);
|
|
790
|
+
referrerUrl?: (Scalars['String'] | null);
|
|
791
|
+
screenHeight?: (Scalars['Int'] | null);
|
|
792
|
+
screenWidth?: (Scalars['Int'] | null);
|
|
793
|
+
submissionMethod?: (Scalars['String'] | null);
|
|
794
|
+
submittedAt?: (Scalars['DateTime'] | null);
|
|
795
|
+
timezone?: (Scalars['String'] | null);
|
|
796
|
+
userAgent?: (Scalars['String'] | null);
|
|
797
|
+
}
|
|
798
|
+
interface PostSubscriptionSmsInput {
|
|
799
|
+
/** SMS message body delivered to the subscriber. */
|
|
800
|
+
body: Scalars['String'];
|
|
801
|
+
/** Optional MMS media URLs (image links) attached to the SMS. */
|
|
802
|
+
mediaUrls?: (Scalars['String'][] | null);
|
|
803
|
+
}
|
|
804
|
+
interface PostSubscriptionEmailInput {
|
|
805
|
+
/** Email subject line. */
|
|
806
|
+
subject: Scalars['String'];
|
|
807
|
+
/** Plain-text or markdown body. Rendered via React Email. */
|
|
808
|
+
body: Scalars['String'];
|
|
809
|
+
}
|
|
810
|
+
interface PostSubscriptionPushInput {
|
|
811
|
+
/** Push notification title. */
|
|
812
|
+
title: Scalars['String'];
|
|
813
|
+
/** Push notification body. */
|
|
814
|
+
body: Scalars['String'];
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Welcome message delivered after a successful subscription. Each channel is independent —
|
|
818
|
+
* provide any combination of sms, email, and push. Channels with no input are skipped.
|
|
819
|
+
* The message is sent at most once per active subscription period (atomic per-channel claim).
|
|
820
|
+
*/
|
|
821
|
+
interface PostSubscriptionMessageInput {
|
|
822
|
+
sms?: (PostSubscriptionSmsInput | null);
|
|
823
|
+
email?: (PostSubscriptionEmailInput | null);
|
|
824
|
+
push?: (PostSubscriptionPushInput | null);
|
|
825
|
+
}
|
|
826
|
+
interface CreatePartnerBrandSubscriptionInput {
|
|
827
|
+
compliance?: (SubscriptionComplianceInput | null);
|
|
828
|
+
email?: (Scalars['String'] | null);
|
|
829
|
+
/** Optional full name. If provided, include first and last name. */
|
|
830
|
+
fullName?: (Scalars['String'] | null);
|
|
831
|
+
/** Optional brand list names to attach the subscribed user to. Missing lists are created automatically. */
|
|
832
|
+
listNames?: (Scalars['String'][] | null);
|
|
833
|
+
/** E.164 phone number (for example +14155551234) */
|
|
834
|
+
phoneNumber: Scalars['String'];
|
|
835
|
+
requireOtpVerification?: (Scalars['Boolean'] | null);
|
|
836
|
+
/**
|
|
837
|
+
* Optional welcome message to deliver via the chosen channels. Sent at most once per active
|
|
838
|
+
* subscription period — safe to retry. Email requires the user to have a primary email and
|
|
839
|
+
* the brand to have a configured email alias. Push requires the user to have at least one
|
|
840
|
+
* push token and to not have opted out of brand messages.
|
|
841
|
+
*/
|
|
842
|
+
postSubscriptionMessage?: (PostSubscriptionMessageInput | null);
|
|
843
|
+
}
|
|
844
|
+
interface VerifyPartnerBrandSubscriptionInput {
|
|
845
|
+
code: Scalars['String'];
|
|
846
|
+
verificationToken: Scalars['String'];
|
|
847
|
+
}
|
|
716
848
|
/**
|
|
717
849
|
* A presigned S3 upload URL and the generated filename.
|
|
718
850
|
* Returned by getPartnerUploadUrl.
|
|
@@ -745,6 +877,13 @@ interface MediaAssetGenqlSelection {
|
|
|
745
877
|
__typename?: boolean | number;
|
|
746
878
|
__scalar?: boolean | number;
|
|
747
879
|
}
|
|
880
|
+
interface CreatePartnerBrandSubscriptionResponseGenqlSelection {
|
|
881
|
+
subscription?: BrandSubscriptionGenqlSelection;
|
|
882
|
+
verificationRequired?: boolean | number;
|
|
883
|
+
verificationToken?: boolean | number;
|
|
884
|
+
__typename?: boolean | number;
|
|
885
|
+
__scalar?: boolean | number;
|
|
886
|
+
}
|
|
748
887
|
interface MutationGenqlSelection {
|
|
749
888
|
/**
|
|
750
889
|
* Get a presigned S3 URL for direct file upload.
|
|
@@ -767,6 +906,15 @@ interface MutationGenqlSelection {
|
|
|
767
906
|
dimensions: DimensionsInput;
|
|
768
907
|
};
|
|
769
908
|
});
|
|
909
|
+
/**
|
|
910
|
+
* Subscribe a user to the authenticated partner brand.
|
|
911
|
+
* Set requireOtpVerification to true to start a two-step OTP flow.
|
|
912
|
+
*/
|
|
913
|
+
createPartnerBrandSubscription?: (CreatePartnerBrandSubscriptionResponseGenqlSelection & {
|
|
914
|
+
__args: {
|
|
915
|
+
input: CreatePartnerBrandSubscriptionInput;
|
|
916
|
+
};
|
|
917
|
+
});
|
|
770
918
|
/**
|
|
771
919
|
* Create a moment with optional venue and ticket tiers in one atomic operation.
|
|
772
920
|
* When type is IRL, the venue field is required.
|
|
@@ -776,6 +924,12 @@ interface MutationGenqlSelection {
|
|
|
776
924
|
input: CreatePartnerMomentInput;
|
|
777
925
|
};
|
|
778
926
|
});
|
|
927
|
+
/** Complete a partner brand subscription that was created with requireOtpVerification=true. */
|
|
928
|
+
verifyPartnerBrandSubscription?: (BrandSubscriptionGenqlSelection & {
|
|
929
|
+
__args: {
|
|
930
|
+
input: VerifyPartnerBrandSubscriptionInput;
|
|
931
|
+
};
|
|
932
|
+
});
|
|
779
933
|
__typename?: boolean | number;
|
|
780
934
|
__scalar?: boolean | number;
|
|
781
935
|
}
|
|
@@ -838,6 +992,9 @@ declare const generateMutationOp: (fields: MutationGenqlSelection & {
|
|
|
838
992
|
* Default ITM backend production API endpoint.
|
|
839
993
|
*/
|
|
840
994
|
declare const DEFAULT_API_URL = "https://itm-backend-production.up.railway.app/graphql";
|
|
995
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
996
|
+
type ITMPartnerHeadersObject = Record<string, string>;
|
|
997
|
+
type ITMPartnerHeaders = ITMPartnerHeadersObject | (() => MaybePromise<ITMPartnerHeadersObject | undefined>);
|
|
841
998
|
interface ITMPartnerClientConfig {
|
|
842
999
|
/**
|
|
843
1000
|
* Partner API token (from backstage: Settings > Partner API).
|
|
@@ -851,8 +1008,10 @@ interface ITMPartnerClientConfig {
|
|
|
851
1008
|
baseUrl?: string;
|
|
852
1009
|
/**
|
|
853
1010
|
* Additional headers to include on every request.
|
|
1011
|
+
* A function is useful for request-scoped values like `x-forwarded-for`
|
|
1012
|
+
* and `user-agent` when proxying end-user traffic through your server.
|
|
854
1013
|
*/
|
|
855
|
-
headers?:
|
|
1014
|
+
headers?: ITMPartnerHeaders;
|
|
856
1015
|
}
|
|
857
1016
|
type ITMPartnerClient = Client;
|
|
858
1017
|
/**
|
|
@@ -885,4 +1044,4 @@ type ITMPartnerClient = Client;
|
|
|
885
1044
|
*/
|
|
886
1045
|
declare function createITMPartnerClient(config: ITMPartnerClientConfig): ITMPartnerClient;
|
|
887
1046
|
|
|
888
|
-
export { type CreatePartnerMomentInput, type CreatePartnerTicketTierInput, type Currency, DEFAULT_API_URL, type Dimensions, type DimensionsInput, type Echo, type EchoMediaAsset, type EchoType, type GetBrandEchoesForUserResponse, type GetPartnerCustomersResponse, type GetPublicMomentsResponse, type GetTicketsResponse, type ITMPartnerClient, type ITMPartnerClientConfig, type MediaAsset, type MediaAssetUploadUrl, type MerchPurchase, type Moment, type MomentCategory, type MomentCollection, type MomentCollectionLink, type MomentDiscountCodeUsage, type MomentSortOrder, type MomentStatus, type MomentSubcategory, type MomentType, type Mutation, type PartnerCustomer, type Payment, type PaymentStatus, type Query, type ThirdPartyEchoType, type Ticket, type TicketExtension, type TicketExtensionStatus, type TicketTier, type User, type Venue, type VenueInput, createITMPartnerClient, everything, generateMutationOp, generateQueryOp };
|
|
1047
|
+
export { type BrandSubscription, type CreatePartnerBrandSubscriptionInput, type CreatePartnerBrandSubscriptionResponse, type CreatePartnerMomentInput, type CreatePartnerTicketTierInput, type Currency, DEFAULT_API_URL, type Dimensions, type DimensionsInput, type Echo, type EchoMediaAsset, type EchoType, type GetBrandEchoesForUserResponse, type GetPartnerCustomersResponse, type GetPublicMomentsResponse, type GetTicketsResponse, type ITMPartnerClient, type ITMPartnerClientConfig, type ITMPartnerHeaders, type ITMPartnerHeadersObject, type MediaAsset, type MediaAssetUploadUrl, type MerchPurchase, type Moment, type MomentCategory, type MomentCollection, type MomentCollectionLink, type MomentDiscountCodeUsage, type MomentSortOrder, type MomentStatus, type MomentSubcategory, type MomentType, type Mutation, type PartnerCustomer, type PartnerMomentStats, type Payment, type PaymentStatus, type PostSubscriptionEmailInput, type PostSubscriptionMessageInput, type PostSubscriptionPushInput, type PostSubscriptionSmsInput, type Query, type SubscriptionComplianceInput, type ThirdPartyEchoType, type Ticket, type TicketExtension, type TicketExtensionStatus, type TicketTier, type User, type Venue, type VenueInput, type VerifyPartnerBrandSubscriptionInput, createITMPartnerClient, everything, generateMutationOp, generateQueryOp };
|