@itm-studio/partner-sdk 0.2.3 → 0.2.4

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 (2) hide show
  1. package/README.md +120 -1
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -369,7 +369,7 @@ Use OTP subscribe when you want the user to confirm the phone number before the
369
369
  - `listNames`: optional brand list names. Missing lists are created automatically and the subscribed user is attached to them.
370
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
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).
372
+ - `postSubscriptionMessage`: optional welcome message delivered automatically after the subscription becomes active. The SDK exposes this as `PostSubscriptionMessageInput` and accepts it on `CreatePartnerBrandSubscriptionInput`. See [Post-Subscription Welcome Message](#post-subscription-welcome-message).
373
373
 
374
374
  ### OTP Flow Step By Step
375
375
 
@@ -388,6 +388,37 @@ If the verification token is invalid or expired, verification fails and the subs
388
388
 
389
389
  **Channels are independent.** Provide any combination of `sms`, `email`, and `push`. Channels you omit are skipped.
390
390
 
391
+ The field is part of the generated SDK input types:
392
+
393
+ ```typescript
394
+ import type {
395
+ CreatePartnerBrandSubscriptionInput,
396
+ PostSubscriptionMessageInput,
397
+ } from '@itm-studio/partner-sdk';
398
+
399
+ const welcomeMessage: PostSubscriptionMessageInput = {
400
+ sms: {
401
+ body: 'Welcome to Acme. Reply STOP to opt out.',
402
+ mediaUrls: ['https://cdn.example.com/welcome-banner.png'],
403
+ },
404
+ email: {
405
+ subject: 'Welcome to Acme',
406
+ body: 'Thanks for subscribing. Your first update is on the way.',
407
+ },
408
+ push: {
409
+ title: 'Welcome to Acme',
410
+ body: 'Tap to see what is dropping this week.',
411
+ },
412
+ };
413
+
414
+ const input: CreatePartnerBrandSubscriptionInput = {
415
+ phoneNumber: '+14155550111',
416
+ fullName: 'Jane Doe',
417
+ email: 'jane@example.com',
418
+ postSubscriptionMessage: welcomeMessage,
419
+ };
420
+ ```
421
+
391
422
  ```typescript
392
423
  await itm.mutation({
393
424
  createPartnerBrandSubscription: {
@@ -418,6 +449,15 @@ await itm.mutation({
418
449
  });
419
450
  ```
420
451
 
452
+ **Direct vs OTP timing:**
453
+
454
+ | Mode | Where to pass `postSubscriptionMessage` | When delivery starts |
455
+ |---|---|---|
456
+ | Direct subscribe | Initial `createPartnerBrandSubscription` call | After the subscription is created or reactivated |
457
+ | OTP subscribe | Initial `createPartnerBrandSubscription` call with `requireOtpVerification: true` | After `verifyPartnerBrandSubscription` succeeds |
458
+
459
+ Do not pass `postSubscriptionMessage` to `verifyPartnerBrandSubscription`; that mutation only accepts `verificationToken` and `code`.
460
+
421
461
  **Channel inputs:**
422
462
 
423
463
  | Channel | Required | Optional | Notes |
@@ -432,12 +472,76 @@ await itm.mutation({
432
472
  - The message is delivered when the subscription is **newly created or reactivated** — re-subscribing an already-active user is a no-op.
433
473
  - In OTP mode, the message fires **after** `verifyPartnerBrandSubscription` succeeds, not when the OTP is requested.
434
474
  - Channel failures are isolated: if email cannot be sent because the user has no primary email, SMS and push are still attempted.
475
+ - Delivery is asynchronous. A successful mutation means the subscription request was accepted; it does not mean each SMS, email, or push provider has already completed delivery.
435
476
 
436
477
  **Recommended usage:**
437
478
 
438
479
  - 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
480
  - 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
481
  - 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.
482
+ - Keep message content deterministic for a signup attempt. Because delivery is idempotent per active subscription period, retrying the same create call is safe; changing the message between retries should not be used as an update mechanism.
483
+
484
+ **Minimal SMS-only example:**
485
+
486
+ ```typescript
487
+ await itm.mutation({
488
+ createPartnerBrandSubscription: {
489
+ __args: {
490
+ input: {
491
+ phoneNumber: '+14155550111',
492
+ postSubscriptionMessage: {
493
+ sms: {
494
+ body: 'You are subscribed to Acme updates. Reply STOP to opt out.',
495
+ },
496
+ },
497
+ },
498
+ },
499
+ verificationRequired: true,
500
+ subscription: { uid: true },
501
+ },
502
+ });
503
+ ```
504
+
505
+ **OTP example with buffered welcome message:**
506
+
507
+ ```typescript
508
+ const { createPartnerBrandSubscription } = await itm.mutation({
509
+ createPartnerBrandSubscription: {
510
+ __args: {
511
+ input: {
512
+ phoneNumber: '+14155550112',
513
+ requireOtpVerification: true,
514
+ email: 'jane@example.com',
515
+ postSubscriptionMessage: {
516
+ sms: {
517
+ body: 'Thanks for joining Acme. Reply STOP to opt out.',
518
+ },
519
+ email: {
520
+ subject: 'You are subscribed',
521
+ body: 'Your subscription is confirmed. We will send updates here.',
522
+ },
523
+ },
524
+ },
525
+ },
526
+ verificationRequired: true,
527
+ verificationToken: true,
528
+ },
529
+ });
530
+
531
+ // Later, after collecting the SMS code from the user:
532
+ await itm.mutation({
533
+ verifyPartnerBrandSubscription: {
534
+ __args: {
535
+ input: {
536
+ verificationToken: createPartnerBrandSubscription.verificationToken!,
537
+ code: '123456',
538
+ },
539
+ },
540
+ uid: true,
541
+ isActive: true,
542
+ },
543
+ });
544
+ ```
441
545
 
442
546
  ### `createPartnerBrandSubscription`
443
547
 
@@ -446,6 +550,7 @@ Subscribe a phone number to the authenticated partner brand.
446
550
  - Omit `requireOtpVerification` or set it to `false` to create the subscription immediately.
447
551
  - Set `requireOtpVerification: true` to start the OTP flow. The backend sends the code to the provided phone number and returns a `verificationToken`.
448
552
  - If you pass `fullName`, include both first and last name.
553
+ - Pass `postSubscriptionMessage` here if you want SMS, email, or push sent after activation. This field is accepted only on the create mutation, including OTP starts.
449
554
 
450
555
  ```typescript
451
556
  const { createPartnerBrandSubscription } = await itm.mutation({
@@ -460,6 +565,11 @@ const { createPartnerBrandSubscription } = await itm.mutation({
460
565
  pageUrl: 'https://example.com/signup',
461
566
  submissionMethod: 'partner_sdk',
462
567
  },
568
+ postSubscriptionMessage: {
569
+ sms: {
570
+ body: 'Welcome to Acme updates. Reply STOP to opt out.',
571
+ },
572
+ },
463
573
  },
464
574
  },
465
575
  verificationRequired: true,
@@ -580,6 +690,15 @@ export async function startOtpSubscription(request: Request) {
580
690
  submittedAt: new Date().toISOString(),
581
691
  timezone: 'America/New_York',
582
692
  },
693
+ postSubscriptionMessage: {
694
+ sms: {
695
+ body: 'You are subscribed. Reply STOP to opt out.',
696
+ },
697
+ email: {
698
+ subject: 'Welcome',
699
+ body: 'Your subscription is confirmed.',
700
+ },
701
+ },
583
702
  },
584
703
  },
585
704
  verificationRequired: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itm-studio/partner-sdk",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "TypeScript SDK for the ITM Partner API — typed GraphQL client with zero introspection required",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -21,7 +21,7 @@
21
21
  "build": "npm run generate && tsup",
22
22
  "test": "vitest run",
23
23
  "test:watch": "vitest",
24
- "lint": "tsc --noEmit",
24
+ "lint": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.test.json",
25
25
  "prepublishOnly": "npm run build",
26
26
  "schema:check": "hive schema:check ./schema/partner.graphql",
27
27
  "schema:publish": "hive schema:publish ./schema/partner.graphql --author \"CI\" --commit \"$GITHUB_SHA\""