@proveanything/smartlinks 1.3.35 → 1.3.38

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.
@@ -0,0 +1,869 @@
1
+ # Proof Claiming Methods
2
+
3
+ SmartLinks supports multiple methods for claiming/registering product ownership. Each method serves different use cases and product types.
4
+
5
+ ---
6
+
7
+ ## Overview of Claiming Methods
8
+
9
+ | Method | Use Case | Requires Physical ID? | SDK Function |
10
+ |--------|----------|---------------------|--------------|
11
+ | **Tag-Based (NFC/QR)** | Physical products with tags | ✅ Yes | `proof.claim(collectionId, productId, proofId, data)` |
12
+ | **Serial Number** | Products with printed codes | ✅ Yes | `proof.claim(collectionId, productId, proofId, data)` |
13
+ | **Claimable/Virtual Proof** | Pre-allocated proofs (tickets, licenses) | ✅ Yes* | `proof.claim(collectionId, productId, proofId, data)` |
14
+ | **Auto-Generated** | Generic product registration | ❌ No | `proof.claimProduct(collectionId, productId, data)` |
15
+
16
+ *Proof ID provided via email/link rather than physical product
17
+
18
+ ---
19
+
20
+ ## Method 1-3: Claim with Proof ID
21
+
22
+ **Use when:** You have a proof ID from an NFC tag, QR code, serial number, or pre-allocated proof.
23
+
24
+ ### API
25
+
26
+ ```typescript
27
+ import { proof } from '@proveanything/smartlinks';
28
+
29
+ const claimed = await proof.claim(
30
+ collectionId, // e.g., 'wine-collection'
31
+ productId, // e.g., 'bordeaux-2020'
32
+ proofId, // e.g., 'abc123-XY7Z' or 'a7Bx3'
33
+ {
34
+ // Optional: additional data
35
+ purchaseDate: '2026-02-17',
36
+ notes: 'First bottle from this vintage'
37
+ }
38
+ );
39
+
40
+ console.log('Claimed proof:', claimed.id);
41
+ console.log('Owner:', claimed.userId);
42
+ ```
43
+
44
+ ### Examples by ID Type
45
+
46
+ **NFC Tag ID:**
47
+ ```typescript
48
+ // User scans NFC tag, app reads tag ID
49
+ const tagId = "abc123-XY7Z";
50
+
51
+ const claimed = await proof.claim(
52
+ 'wine-collection',
53
+ 'bordeaux-2020',
54
+ tagId
55
+ );
56
+ ```
57
+
58
+ **Serial Number:**
59
+ ```typescript
60
+ // User types in serial from product packaging
61
+ const serial = "a7Bx3";
62
+
63
+ const claimed = await proof.claim(
64
+ 'electronics',
65
+ 'headphones-pro',
66
+ serial,
67
+ { warranty: true }
68
+ );
69
+ ```
70
+
71
+ **Pre-allocated Proof (Ticket/License):**
72
+ ```typescript
73
+ // User received proof ID via email
74
+ const ticketId = "TICKET-VIP-001";
75
+
76
+ const claimed = await proof.claim(
77
+ 'event-2026',
78
+ 'vip-ticket',
79
+ ticketId
80
+ );
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Method 4: Auto-Generated Claims
86
+
87
+ **Use when:** Product doesn't have unique identifiers, or you want simple post-purchase registration.
88
+
89
+ ### Requirements
90
+
91
+ The collection or product must have `allowAutoGenerateClaims` enabled. Apps will know if this is available based on product configuration.
92
+
93
+ ### API
94
+
95
+ ```typescript
96
+ import { proof } from '@proveanything/smartlinks';
97
+
98
+ // No proof ID needed - system generates one automatically
99
+ const claimed = await proof.claimProduct(
100
+ collectionId, // e.g., 'beauty-brand'
101
+ productId, // e.g., 'moisturizer-pro'
102
+ {
103
+ // Optional: user data
104
+ purchaseDate: '2026-02-17',
105
+ store: 'Target',
106
+ notes: 'Love this product!'
107
+ }
108
+ );
109
+
110
+ console.log('Auto-generated ID:', claimed.id); // e.g., "a7Bx3"
111
+ console.log('You now own this product');
112
+ ```
113
+
114
+ ### When to Use
115
+
116
+ ✅ **Good for:**
117
+ - Consumer products (cosmetics, household goods)
118
+ - Post-purchase registration
119
+ - Products without unique identifiers
120
+ - Building product collections/wishlists
121
+
122
+ ❌ **Avoid for:**
123
+ - High-value items
124
+ - Limited editions
125
+ - Products requiring proof of purchase
126
+ - Authenticity verification
127
+
128
+ ---
129
+
130
+ ## Choosing the Right Method
131
+
132
+ Apps typically know which method to use based on product configuration:
133
+
134
+ ```typescript
135
+ const product = await product.get(collectionId, productId);
136
+
137
+ if (product.admin?.allowAutoGenerateClaims) {
138
+ // Show simple registration button
139
+ return <RegisterButton onClick={() =>
140
+ proof.claimProduct(collectionId, productId, userData)
141
+ } />;
142
+ } else {
143
+ // Show input field for proof ID
144
+ return <ClaimForm onSubmit={(proofId) =>
145
+ proof.claim(collectionId, productId, proofId, userData)
146
+ } />;
147
+ }
148
+ ```
149
+
150
+ ### Decision Tree
151
+
152
+ ```
153
+ Do you have a proof ID?
154
+ ├─ YES → Use proof.claim(collectionId, productId, proofId, data)
155
+ └─ NO → Use proof.claimProduct(collectionId, productId, data)
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Complete Examples
161
+
162
+ ### Beauty Product Registration (Auto-Claim)
163
+
164
+ ```typescript
165
+ import { proof } from '@proveanything/smartlinks';
166
+
167
+ async function registerProduct() {
168
+ try {
169
+ const claimed = await proof.claimProduct(
170
+ 'beauty-brand',
171
+ 'moisturizer-pro',
172
+ {
173
+ purchaseDate: '2026-02-17',
174
+ store: 'Sephora',
175
+ skinType: 'combination'
176
+ }
177
+ );
178
+
179
+ alert(`Product registered! Your ID is: ${claimed.id}`);
180
+ // Navigate to product dashboard
181
+
182
+ } catch (error) {
183
+ if (error.errorCode === 'FEATURE_NOT_ENABLED') {
184
+ alert('This product requires a code to register');
185
+ } else {
186
+ alert('Registration failed. Please try again.');
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ ### Wine Bottle Authentication (NFC Tag)
193
+
194
+ ```typescript
195
+ import { proof } from '@proveanything/smartlinks';
196
+
197
+ async function claimWineBottle(tagId: string) {
198
+ try {
199
+ const claimed = await proof.claim(
200
+ 'wine-collection',
201
+ 'bordeaux-2020',
202
+ tagId,
203
+ {
204
+ purchaseDate: '2026-02-17',
205
+ vendor: 'Fine Wine Shop',
206
+ cellarLocation: 'Rack 3, Position 12'
207
+ }
208
+ );
209
+
210
+ console.log('Bottle authenticated and claimed!');
211
+ console.log('Proof ID:', claimed.id);
212
+
213
+ } catch (error) {
214
+ if (error.status === 404) {
215
+ alert('Invalid tag ID');
216
+ } else if (error.status === 409) {
217
+ alert('This bottle is already claimed');
218
+ }
219
+ }
220
+ }
221
+
222
+ // User scans NFC tag
223
+ nfcReader.addEventListener('reading', ({ serialNumber }) => {
224
+ claimWineBottle(serialNumber);
225
+ });
226
+ ```
227
+
228
+ ### Event Ticket Claiming
229
+
230
+ ```typescript
231
+ import { proof } from '@proveanything/smartlinks';
232
+
233
+ async function claimTicket(ticketId: string) {
234
+ const claimed = await proof.claim(
235
+ 'music-festival-2026',
236
+ 'vip-pass',
237
+ ticketId
238
+ );
239
+
240
+ console.log('Ticket claimed!');
241
+ console.log('Seat:', claimed.data.seatNumber);
242
+ console.log('Access level:', claimed.data.tier);
243
+ }
244
+
245
+ // User clicks email link with ticket ID
246
+ const urlParams = new URLSearchParams(window.location.search);
247
+ const ticketId = urlParams.get('ticket');
248
+ if (ticketId) {
249
+ claimTicket(ticketId);
250
+ }
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Error Handling
256
+
257
+ ### Common Errors
258
+
259
+ ```typescript
260
+ try {
261
+ const claimed = await proof.claimProduct(collectionId, productId, data);
262
+ } catch (error) {
263
+ switch (error.errorCode) {
264
+ case 'FEATURE_NOT_ENABLED':
265
+ // Auto-claim not enabled for this product
266
+ // Fall back to proof ID input
267
+ break;
268
+
269
+ case 'NOT_AUTHORIZED':
270
+ // User not logged in
271
+ // Redirect to login
272
+ break;
273
+
274
+ case 'RATE_LIMIT_EXCEEDED':
275
+ // Too many claims
276
+ // Show retry message
277
+ break;
278
+
279
+ case 'ALREADY_CLAIMED':
280
+ // Proof ID already claimed by another user
281
+ break;
282
+
283
+ default:
284
+ // Generic error handling
285
+ break;
286
+ }
287
+ }
288
+ ```
289
+
290
+ ---
291
+
292
+ ## API Reference
293
+
294
+ ### `proof.claim(collectionId, productId, proofId, data?)`
295
+
296
+ Claim a proof using an existing proof ID (NFC tag, serial number, pre-allocated proof).
297
+
298
+ **Parameters:**
299
+ - `collectionId` (string) - Collection ID
300
+ - `productId` (string) - Product ID
301
+ - `proofId` (string) - The proof ID to claim
302
+ - `data` (object, optional) - Additional data to attach to the proof
303
+
304
+ **Returns:** `Promise<ProofResponse>`
305
+
306
+ **Endpoint:** `PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim`
307
+
308
+ ---
309
+
310
+ ### `proof.claimProduct(collectionId, productId, data?)`
311
+
312
+ Claim a product without a proof ID. System auto-generates a unique serial number.
313
+
314
+ **Parameters:**
315
+ - `collectionId` (string) - Collection ID
316
+ - `productId` (string) - Product ID
317
+ - `data` (object, optional) - User data to attach to the proof
318
+
319
+ **Returns:** `Promise<ProofResponse>` with auto-generated `id` field
320
+
321
+ **Endpoint:** `PUT /public/collection/:collectionId/product/:productId/proof/claim`
322
+
323
+ **Requirements:** Collection or product must have `allowAutoGenerateClaims: true`
324
+
325
+ ---
326
+
327
+ ## TypeScript Definitions
328
+
329
+ ### Collection
330
+
331
+ ```typescript
332
+ interface Collection {
333
+ // ... other fields
334
+ allowAutoGenerateClaims?: boolean // Enable auto-claim for all products
335
+ }
336
+ ```
337
+
338
+ ### Product
339
+
340
+ ```typescript
341
+ interface Product {
342
+ // ... other fields
343
+ admin?: {
344
+ allowAutoGenerateClaims?: boolean // Override collection setting
345
+ lastSerialId?: number // Last generated serial (auto-incremented)
346
+ }
347
+ }
348
+ ```
349
+
350
+ ---
351
+
352
+ **Last Updated:** February 17, 2026
353
+
354
+ ---
355
+
356
+ ## Overview of Claiming Methods
357
+
358
+ | Method | Use Case | Requires Physical ID? | Pre-Generation? | SDK Function |
359
+ |--------|----------|---------------------|----------------|--------------|
360
+ | **1. Tag-Based (NFC/QR)** | Physical products with tags | ✅ Yes | ✅ Yes | `proof.claim(proofId)` |
361
+ | **2. Serial Number** | Products with printed codes | ✅ Yes | ✅ Yes | `proof.claim(proofId)` |
362
+ | **3. Claimable Proof** | Pre-allocated virtual proofs | ❌ No* | ✅ Yes | `proof.claim(proofId)` |
363
+ | **4. Virtual Proof** | Digital-only products | ❌ No | ✅ Yes | `proof.claim(proofId)` |
364
+ | **5. Auto-Generated (NEW)** | Generic product registration | ❌ No | ❌ No | `proof.claimProduct()` |
365
+
366
+ *Claimable proofs have a proof ID but user may receive it via email/link rather than physical product
367
+
368
+ ---
369
+
370
+ ## Method 1: Tag-Based Claims (NFC/QR)
371
+
372
+ **Best for:** Physical products with embedded NFC chips or printed QR codes
373
+
374
+ ### How It Works
375
+
376
+ 1. Admin pre-generates claim sets with unique tag IDs
377
+ 2. Physical tags are attached to products
378
+ 3. User scans tag with phone → reads tag ID
379
+ 4. User claims proof using tag ID
380
+
381
+ ### Proof ID Format
382
+
383
+ ```
384
+ {claimSetId}-{code}
385
+ Example: "abc123-XY7Z"
386
+ ```
387
+
388
+ ### Implementation
389
+
390
+ **Admin: Generate claim set**
391
+ ```typescript
392
+ import { claimSet } from '@proveanything/smartlinks';
393
+
394
+ const result = await claimSet.create({
395
+ collectionId: 'wine-collection',
396
+ productId: 'bordeaux-2020',
397
+ count: 1000, // Generate 1000 unique tags
398
+ type: 'nfc' // or 'qr'
399
+ });
400
+
401
+ // Returns: { ids: ["abc123-0001", "abc123-0002", ...] }
402
+ ```
403
+
404
+ **User: Claim via tag**
405
+ ```typescript
406
+ import { proof } from '@proveanything/smartlinks';
407
+
408
+ // User scans NFC tag, app reads tag ID
409
+ const tagId = "abc123-XY7Z";
410
+
411
+ const claimed = await proof.claim(tagId, {
412
+ collectionId: 'wine-collection',
413
+ productId: 'bordeaux-2020'
414
+ });
415
+
416
+ console.log('Claimed:', claimed.id);
417
+ ```
418
+
419
+ ### Advantages
420
+ - ✅ Highly secure (physical possession required)
421
+ - ✅ Simple user experience (tap phone)
422
+ - ✅ Works offline (scan → claim later)
423
+
424
+ ### Disadvantages
425
+ - ❌ Requires physical tags (cost)
426
+ - ❌ Tags can be lost/damaged
427
+ - ❌ Pre-generation needed
428
+
429
+ ---
430
+
431
+ ## Method 2: Serial Number Claims
432
+
433
+ **Best for:** Products with printed serial numbers
434
+
435
+ ### How It Works
436
+
437
+ 1. Admin generates batch of serial numbers
438
+ 2. Serial numbers printed on product packaging
439
+ 3. User manually enters serial number
440
+ 4. System validates and claims proof
441
+
442
+ ### Proof ID Format
443
+
444
+ ```
445
+ Base62-encoded with HMAC validation
446
+ Example: "a7Bx3", "K9mP2"
447
+ ```
448
+
449
+ ### Implementation
450
+
451
+ **Admin: Generate serial numbers**
452
+ ```typescript
453
+ import { serialNumber } from '@proveanything/smartlinks';
454
+
455
+ const serials = await serialNumber.generate({
456
+ collectionId: 'electronics',
457
+ productId: 'headphones-pro',
458
+ count: 5000,
459
+ startIndex: 1000 // Optional: continue from previous batch
460
+ });
461
+
462
+ // Returns: ["a7Bx3", "a8Cy4", ...]
463
+ // Print these on product packaging
464
+ ```
465
+
466
+ **User: Claim via serial**
467
+ ```typescript
468
+ import { proof } from '@proveanything/smartlinks';
469
+
470
+ // User types in serial from product
471
+ const serial = "a7Bx3";
472
+
473
+ const claimed = await proof.claim(serial, {
474
+ collectionId: 'electronics',
475
+ productId: 'headphones-pro'
476
+ });
477
+
478
+ console.log('Product registered:', claimed.id);
479
+ ```
480
+
481
+ ### Advantages
482
+ - ✅ Lower cost (just printing)
483
+ - ✅ Works on any product
484
+ - ✅ Cryptographically secure
485
+
486
+ ### Disadvantages
487
+ - ❌ User must manually type code (typos)
488
+ - ❌ Codes can be shared/leaked
489
+ - ❌ Pre-generation needed
490
+
491
+ ---
492
+
493
+ ## Method 3: Claimable Proof Claims
494
+
495
+ **Best for:** Event tickets, vouchers, promotional items
496
+
497
+ ### How It Works
498
+
499
+ 1. Admin creates claimable proofs (virtual state)
500
+ 2. Proof IDs distributed via email/link
501
+ 3. User clicks claim link or enters proof ID
502
+ 4. Proof transitions from virtual → claimed
503
+
504
+ ### Proof ID Format
505
+
506
+ ```
507
+ Custom proof ID set by admin
508
+ Example: "TICKET-2026-001", "VOUCHER-ABC"
509
+ ```
510
+
511
+ ### Implementation
512
+
513
+ **Admin: Create claimable proofs**
514
+ ```typescript
515
+ import { proof } from '@proveanything/smartlinks';
516
+
517
+ // Create single claimable proof
518
+ const claimableProof = await proof.create({
519
+ collectionId: 'event-2026',
520
+ productId: 'vip-ticket',
521
+ id: 'TICKET-VIP-001',
522
+ admin: true,
523
+ data: {
524
+ claimable: true, // Marks as unclaimed
525
+ virtual: true, // Not yet associated with user
526
+ seatNumber: 'A-12',
527
+ tier: 'VIP'
528
+ }
529
+ });
530
+
531
+ // Send claim link to user
532
+ const claimUrl = `https://yourapp.com/claim/TICKET-VIP-001`;
533
+ sendEmail(user.email, `Your ticket: ${claimUrl}`);
534
+ ```
535
+
536
+ **User: Claim proof**
537
+ ```typescript
538
+ import { proof } from '@proveanything/smartlinks';
539
+
540
+ const claimed = await proof.claim('TICKET-VIP-001', {
541
+ collectionId: 'event-2026',
542
+ productId: 'vip-ticket'
543
+ });
544
+
545
+ // Proof now associated with user
546
+ console.log('Ticket claimed by:', claimed.userId);
547
+ ```
548
+
549
+ ### Advantages
550
+ - ✅ Flexible distribution (email, SMS, link)
551
+ - ✅ Can include pre-configured data
552
+ - ✅ Easy to track claim status
553
+ - ✅ Can set claim windows (time-limited)
554
+
555
+ ### Disadvantages
556
+ - ❌ Requires pre-creation
557
+ - ❌ Link/ID can be shared
558
+ - ❌ More complex admin workflow
559
+
560
+ ---
561
+
562
+ ## Method 4: Virtual Proof Claims
563
+
564
+ **Best for:** Digital products, licenses, access codes
565
+
566
+ ### How It Works
567
+
568
+ Similar to claimable proofs, but typically used for purely digital products without physical counterpart.
569
+
570
+ ### Implementation
571
+
572
+ **Admin: Create virtual proof**
573
+ ```typescript
574
+ import { proof } from '@proveanything/smartlinks';
575
+
576
+ const virtualProof = await proof.create({
577
+ collectionId: 'software-licenses',
578
+ productId: 'photo-editor-pro',
579
+ id: 'LICENSE-2026-XYZ',
580
+ admin: true,
581
+ data: {
582
+ virtual: true,
583
+ claimable: true,
584
+ licenseKey: 'XXXX-YYYY-ZZZZ',
585
+ expiresAt: '2027-12-31'
586
+ }
587
+ });
588
+ ```
589
+
590
+ **User: Claim virtual proof**
591
+ ```typescript
592
+ const claimed = await proof.claim('LICENSE-2026-XYZ', {
593
+ collectionId: 'software-licenses',
594
+ productId: 'photo-editor-pro'
595
+ });
596
+
597
+ console.log('License activated:', claimed.data.licenseKey);
598
+ ```
599
+
600
+ ### Advantages
601
+ - ✅ Perfect for digital goods
602
+ - ✅ No physical logistics
603
+ - ✅ Instant delivery
604
+
605
+ ### Disadvantages
606
+ - ❌ Same as claimable proofs
607
+ - ❌ Codes can be easily shared
608
+
609
+ ---
610
+
611
+ ## Method 5: Auto-Generated Claims (NEW)
612
+
613
+ **Best for:** Generic products without unique identifiers, post-purchase registration
614
+
615
+ ### How It Works
616
+
617
+ 1. Admin enables auto-claim on collection/product
618
+ 2. User initiates claim without proof ID
619
+ 3. System generates unique serial on-the-fly
620
+ 4. Proof created immediately and claimed
621
+
622
+ ### Proof ID Format
623
+
624
+ ```
625
+ Auto-generated Base62 serial
626
+ Example: "a7Bx3", "K9mP2"
627
+ ```
628
+
629
+ ### Implementation
630
+
631
+ **Admin: Enable auto-claim**
632
+ ```typescript
633
+ import { collection } from '@proveanything/smartlinks';
634
+
635
+ // Enable at collection level
636
+ await collection.update('my-collection', {
637
+ allowAutoGenerateClaims: true
638
+ });
639
+
640
+ // Or override at product level
641
+ await product.update('my-collection', 'moisturizer-pro', {
642
+ admin: {
643
+ allowAutoGenerateClaims: true
644
+ }
645
+ });
646
+ ```
647
+
648
+ **User: Claim without proof ID**
649
+ ```typescript
650
+ import { proof } from '@proveanything/smartlinks';
651
+
652
+ // No proof ID needed!
653
+ const claimed = await proof.claimProduct({
654
+ collectionId: 'beauty-brand',
655
+ productId: 'moisturizer-pro',
656
+ data: {
657
+ purchaseDate: '2026-02-17',
658
+ store: 'Target',
659
+ notes: 'Love this product!'
660
+ }
661
+ });
662
+
663
+ console.log('Your product ID:', claimed.id); // Auto-generated: "a7Bx3"
664
+ ```
665
+
666
+ ### API Endpoint
667
+
668
+ ```
669
+ PUT /public/collection/:collectionId/product/:productId/proof/claim
670
+ ```
671
+
672
+ ### Configuration Priority
673
+
674
+ 1. Product `admin.allowAutoGenerateClaims: false` → ❌ Disabled
675
+ 2. Product `admin.allowAutoGenerateClaims: true` → ✅ Enabled
676
+ 3. Collection `allowAutoGenerateClaims: true` → ✅ Enabled
677
+ 4. Default → ❌ Disabled
678
+
679
+ ### Advantages
680
+ - ✅ No pre-generation required
681
+ - ✅ Zero cost (no tags/printing)
682
+ - ✅ Simple user experience
683
+ - ✅ Perfect for non-serialized products
684
+ - ✅ Atomic counter ensures uniqueness
685
+
686
+ ### Disadvantages
687
+ - ❌ No proof of physical ownership
688
+ - ❌ Potential for spam/abuse (needs rate limiting)
689
+ - ❌ Users can claim products they don't own
690
+
691
+ ### Security Considerations
692
+
693
+ **Rate limiting required:**
694
+ ```typescript
695
+ // Limit to 10 auto-claims per hour per user
696
+ if (userClaimCount > 10) {
697
+ throw new Error('Too many claims. Try again later.');
698
+ }
699
+ ```
700
+
701
+ **Use cases where this is safe:**
702
+ - Low-value consumer products
703
+ - Products where ownership doesn't matter much
704
+ - Post-purchase registration for benefits
705
+ - Products sold through verified channels
706
+
707
+ **Avoid for:**
708
+ - High-value items
709
+ - Limited editions
710
+ - Products requiring proof of purchase
711
+ - Collectibles
712
+
713
+ ---
714
+
715
+ ## Choosing the Right Method
716
+
717
+ ### Decision Tree
718
+
719
+ ```
720
+ Does product have a unique physical identifier?
721
+ ├─ YES → Do you need high security?
722
+ │ ├─ YES → NFC Tag (Method 1)
723
+ │ └─ NO → Serial Number (Method 2)
724
+
725
+ └─ NO → Is it a digital product?
726
+ ├─ YES → Virtual Proof (Method 4)
727
+ └─ NO → Do users need proof IDs in advance?
728
+ ├─ YES → Claimable Proof (Method 3)
729
+ └─ NO → Auto-Generated (Method 5)
730
+ ```
731
+
732
+ ### Use Case Examples
733
+
734
+ | Product Type | Recommended Method | Reason |
735
+ |--------------|-------------------|---------|
736
+ | Wine bottles | NFC Tag | High value, authentication important |
737
+ | Electronics | Serial Number | Already have serial numbers |
738
+ | Event tickets | Claimable Proof | Need to distribute in advance |
739
+ | Software licenses | Virtual Proof | Digital product |
740
+ | Cosmetics | Auto-Generated | Low value, post-purchase registration |
741
+ | Limited sneakers | NFC Tag | High value, prevent fraud |
742
+ | Household goods | Auto-Generated | Simple registration, low fraud risk |
743
+
744
+ ---
745
+
746
+ ## Combining Methods
747
+
748
+ You can use multiple methods for the same product:
749
+
750
+ ```typescript
751
+ // Product supports both serial numbers AND auto-claim
752
+ const product = {
753
+ id: 'premium-headphones',
754
+ serialNumbersEnabled: true, // Traditional serial claiming
755
+ admin: {
756
+ allowAutoGenerateClaims: true // Also allow auto-claim
757
+ }
758
+ };
759
+
760
+ // User path 1: Has serial from box
761
+ await proof.claim('a7Bx3', { collectionId, productId });
762
+
763
+ // User path 2: Lost box, just wants to register
764
+ await proof.claimProduct({ collectionId, productId });
765
+ ```
766
+
767
+ ---
768
+
769
+ ## API Summary
770
+
771
+ ### All Claim Methods
772
+
773
+ ```typescript
774
+ import { proof } from '@proveanything/smartlinks';
775
+
776
+ // Methods 1-4: Claim with proof ID
777
+ await proof.claim(proofId, {
778
+ collectionId: string,
779
+ productId: string,
780
+ data?: any // Optional additional data
781
+ });
782
+
783
+ // Method 5: Claim without proof ID
784
+ await proof.claimProduct({
785
+ collectionId: string,
786
+ productId: string,
787
+ data?: any // Optional additional data
788
+ });
789
+ ```
790
+
791
+ ### Check Claim Status
792
+
793
+ ```typescript
794
+ const proofData = await proof.get(proofId);
795
+
796
+ if (proofData.claimable && proofData.virtual) {
797
+ console.log('Proof is unclaimed');
798
+ } else if (proofData.userId) {
799
+ console.log('Proof claimed by:', proofData.userId);
800
+ }
801
+ ```
802
+
803
+ ### Admin: Check Product Settings
804
+
805
+ ```typescript
806
+ const product = await product.get(collectionId, productId);
807
+
808
+ // Check what claiming methods are available
809
+ const methods = {
810
+ hasSerialNumbers: product.admin?.lastSerialId > 0,
811
+ allowsAutoClaim: product.admin?.allowAutoGenerateClaims === true,
812
+ hasClaimSets: product.claimSets?.length > 0
813
+ };
814
+
815
+ console.log('Available claiming methods:', methods);
816
+ ```
817
+
818
+ ---
819
+
820
+ ## Migration Guide
821
+
822
+ ### Adding Auto-Claim to Existing Products
823
+
824
+ ```typescript
825
+ // Enable for all cosmetics products
826
+ const products = await product.list('beauty-collection');
827
+
828
+ for (const prod of products) {
829
+ if (prod.category === 'cosmetics') {
830
+ await product.update('beauty-collection', prod.id, {
831
+ admin: {
832
+ ...prod.admin,
833
+ allowAutoGenerateClaims: true
834
+ }
835
+ });
836
+ }
837
+ }
838
+ ```
839
+
840
+ ### Analytics: Track Claim Method
841
+
842
+ ```typescript
843
+ // When creating proof, tag with claim method
844
+ const proof = await proof.create({
845
+ // ... other fields
846
+ metadata: {
847
+ claimMethod: 'auto_generated' | 'serial' | 'nfc' | 'qr' | 'claimable'
848
+ }
849
+ });
850
+
851
+ // Query by method
852
+ const autoClaimedProofs = await firestore
853
+ .collection('ledger')
854
+ .where('metadata.claimMethod', '==', 'auto_generated')
855
+ .get();
856
+ ```
857
+
858
+ ---
859
+
860
+ ## Related Documentation
861
+
862
+ - [Claim Sets](./claim-sets.md) - Managing NFC/QR tag batches
863
+ - [Serial Numbers](./serial-numbers.md) - Cryptographic serial generation
864
+ - [Proof Ownership](./proof-ownership.md) - Managing claimed proofs
865
+ - [User App Data](./app-data-storage.md) - Storing user preferences per proof
866
+
867
+ ---
868
+
869
+ **Last Updated:** February 17, 2026