@the_ro_show/agent-ads-sdk 0.11.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -0
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +113 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +113 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -418,6 +418,255 @@ curl -X POST https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/feedback \
|
|
|
418
418
|
|
|
419
419
|
---
|
|
420
420
|
|
|
421
|
+
## 🎛️ Developer Controls (v0.12.0+)
|
|
422
|
+
|
|
423
|
+
Take control of what ads appear in your app with quality, category, and advertiser filters.
|
|
424
|
+
|
|
425
|
+
### Quality Score Filter
|
|
426
|
+
|
|
427
|
+
Only show ads that meet your quality standards:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
const ad = await client.decideFromContext({
|
|
431
|
+
userMessage: "I need car insurance",
|
|
432
|
+
minQualityScore: 0.8 // Only ads with 0.8+ quality
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Use cases:**
|
|
437
|
+
- **Premium apps**: Set 0.9+ for best-in-class ads only
|
|
438
|
+
- **General apps**: Set 0.7+ for good balance
|
|
439
|
+
- **High-volume apps**: Set 0.5+ to maximize fill rate
|
|
440
|
+
|
|
441
|
+
### Category Controls (IAB Taxonomy 3.0)
|
|
442
|
+
|
|
443
|
+
Filter ads using **IAB Content Taxonomy 3.0** - the industry-standard category system used by Google Ads, Microsoft Ads, and all major ad platforms.
|
|
444
|
+
|
|
445
|
+
**704 categories** across 38 top-level categories with 4-tier hierarchy.
|
|
446
|
+
|
|
447
|
+
#### Discover Available Categories
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// Get all 38 top-level categories
|
|
451
|
+
const tier1 = await client.getCategories({ tier: 1 });
|
|
452
|
+
tier1.categories.forEach(cat => {
|
|
453
|
+
console.log(`${cat.id}: ${cat.name}`);
|
|
454
|
+
});
|
|
455
|
+
// Output: 1: Automotive, 31: Insurance, 150: Attractions, etc.
|
|
456
|
+
|
|
457
|
+
// Get all subcategories of "Automotive" (ID: 1)
|
|
458
|
+
const automotive = await client.getCategories({ parent_id: 1 });
|
|
459
|
+
// Returns: Auto Insurance (31), Auto Repair (34), Auto Buying (30), etc.
|
|
460
|
+
|
|
461
|
+
// Search for insurance-related categories
|
|
462
|
+
const insurance = await client.getCategories({ search: 'insurance' });
|
|
463
|
+
insurance.categories.forEach(cat => {
|
|
464
|
+
console.log(cat.full_path);
|
|
465
|
+
});
|
|
466
|
+
// Output: "Automotive > Auto Insurance", "Personal Finance > Insurance", etc.
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### Filter by Category
|
|
470
|
+
|
|
471
|
+
Use IAB category IDs for precise control:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// Insurance app: Only show insurance ads (by IAB ID)
|
|
475
|
+
const ad = await client.decideFromContext({
|
|
476
|
+
userMessage: "I need car insurance",
|
|
477
|
+
allowedCategories: [31] // 31 = Auto Insurance
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// Block entire "Sensitive Topics" tree (IAB ID: 601)
|
|
481
|
+
// This blocks all gambling, adult content, controversial topics, etc.
|
|
482
|
+
const ad = await client.decideFromContext({
|
|
483
|
+
userMessage: "Help me with something",
|
|
484
|
+
blockedCategories: [601] // Blocks parent + all children
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// Wedding planner: Allow wedding + photography + food
|
|
488
|
+
const ad = await client.decideFromContext({
|
|
489
|
+
userMessage: "Help me plan my wedding",
|
|
490
|
+
allowedCategories: [
|
|
491
|
+
603, // Weddings (Personal Celebrations)
|
|
492
|
+
162, // Photography (Hobbies & Interests)
|
|
493
|
+
190 // Restaurants (Food & Drink)
|
|
494
|
+
]
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Parent-Child Relationships:**
|
|
499
|
+
- Blocking a parent category blocks ALL child categories automatically
|
|
500
|
+
- Example: Blocking `1` (Automotive) blocks Auto Insurance, Auto Repair, etc.
|
|
501
|
+
- Great for compliance: Block `601` (Sensitive Topics) to block gambling, adult, controversial in one go
|
|
502
|
+
|
|
503
|
+
**Important:**
|
|
504
|
+
- If `allowedCategories` is set, `blockedCategories` is ignored
|
|
505
|
+
- IAB category IDs (numbers) are **recommended** - legacy string categories are deprecated (support ends 2026-06-01)
|
|
506
|
+
- Use `getCategories()` API to discover category IDs
|
|
507
|
+
- Empty `allowedCategories: []` is rejected (would block all ads - use `blockedCategories` instead)
|
|
508
|
+
|
|
509
|
+
**Validation rules:**
|
|
510
|
+
- `minQualityScore`: Must be 0.0-1.0
|
|
511
|
+
- `allowedCategories`: Must be non-empty array of strings or numbers
|
|
512
|
+
- `blockedCategories`: Must be array of strings or numbers
|
|
513
|
+
- `blockedAdvertisers`: Must be array of non-empty strings (advertiser IDs)
|
|
514
|
+
|
|
515
|
+
### Advertiser Blocklist
|
|
516
|
+
|
|
517
|
+
Block specific advertisers based on user feedback:
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
const ad = await client.decideFromContext({
|
|
521
|
+
userMessage: "I need legal help",
|
|
522
|
+
blockedAdvertisers: ['adv_abc123', 'adv_xyz789']
|
|
523
|
+
});
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Get advertiser IDs from previous ad responses.
|
|
527
|
+
|
|
528
|
+
## 💰 Revenue Optimization (v0.13.1+)
|
|
529
|
+
|
|
530
|
+
Control revenue vs. relevance tradeoffs with bid and relevance filters.
|
|
531
|
+
|
|
532
|
+
### Minimum CPC Filter
|
|
533
|
+
|
|
534
|
+
Only show ads above a minimum bid threshold:
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
const ad = await client.decideFromContext({
|
|
538
|
+
userMessage: "I need car insurance",
|
|
539
|
+
minCPC: 100 // Only ads bidding ≥$1.00 per click
|
|
540
|
+
});
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**Use cases:**
|
|
544
|
+
- **Premium apps**: `minCPC: 200` for $2+ ads only
|
|
545
|
+
- **High-value verticals**: Filter out low-budget advertisers
|
|
546
|
+
- **Revenue targets**: Ensure minimum revenue per impression
|
|
547
|
+
|
|
548
|
+
### Minimum Relevance Score
|
|
549
|
+
|
|
550
|
+
Only show ads that are semantically relevant:
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
const ad = await client.decideFromContext({
|
|
554
|
+
userMessage: "Help me plan my wedding",
|
|
555
|
+
minRelevanceScore: 0.8 // Only highly relevant ads (0.0-1.0)
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**Use cases:**
|
|
560
|
+
- **Niche apps**: Legal assistant = `0.8+` for specialized content only
|
|
561
|
+
- **User experience**: Filter out loosely related ads
|
|
562
|
+
- **Context matching**: Ensure ads match conversation topic
|
|
563
|
+
- **Default threshold**: Backend uses 0.25 minimum
|
|
564
|
+
|
|
565
|
+
### Ranking Strategy
|
|
566
|
+
|
|
567
|
+
Choose how ads are ranked:
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
// Default: Revenue-optimized (highest bid wins)
|
|
571
|
+
const ad = await client.decideFromContext({
|
|
572
|
+
userMessage: "I need legal help",
|
|
573
|
+
optimizeFor: 'revenue' // Rank by bid × quality × relevance
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// Alternative: Relevance-optimized (best match wins)
|
|
577
|
+
const ad = await client.decideFromContext({
|
|
578
|
+
userMessage: "I need legal help",
|
|
579
|
+
optimizeFor: 'relevance' // Rank by semantic similarity only
|
|
580
|
+
});
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
**Use cases:**
|
|
584
|
+
- **General apps**: `'revenue'` to maximize earnings
|
|
585
|
+
- **Niche apps**: `'relevance'` to prioritize perfect matches over high bids
|
|
586
|
+
- **Premium experiences**: Combine with high `minRelevanceScore` + `'relevance'` ranking
|
|
587
|
+
|
|
588
|
+
**How it works (second-price auction):**
|
|
589
|
+
- **Revenue mode**: Winner ranked by composite score (bid × quality × relevance), pays just enough to beat next ad's composite score + $0.01
|
|
590
|
+
- **Relevance mode**: Winner ranked by semantic similarity, pays just enough to beat next ad in the composite score space + $0.01
|
|
591
|
+
- **Always capped**: Winner never pays more than their max bid (auction integrity guaranteed)
|
|
592
|
+
- **Floor price**: Minimum $0.25 clearing price ensures platform revenue
|
|
593
|
+
|
|
594
|
+
**Important notes:**
|
|
595
|
+
- `minRelevanceScore` only applies to campaigns with semantic targeting
|
|
596
|
+
- For keyword/automatic campaigns, relevance filter has no effect
|
|
597
|
+
- Validation errors return HTTP 400 with clear messages
|
|
598
|
+
|
|
599
|
+
### Combined Revenue Controls
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
// Premium legal assistant: High relevance + high bids
|
|
603
|
+
const ad = await client.decideFromContext({
|
|
604
|
+
userMessage: "I need estate planning help",
|
|
605
|
+
minRelevanceScore: 0.8, // Only highly relevant
|
|
606
|
+
minCPC: 200, // Only $2+ bids
|
|
607
|
+
optimizeFor: 'relevance', // Best match wins
|
|
608
|
+
allowedCategories: [318] // Legal services only (IAB)
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// General chatbot: Maximize revenue
|
|
612
|
+
const ad = await client.decideFromContext({
|
|
613
|
+
userMessage: "Help me with something",
|
|
614
|
+
optimizeFor: 'revenue', // Highest bid wins
|
|
615
|
+
minQualityScore: 0.7 // Decent quality threshold
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Combined Controls (All Phases)
|
|
620
|
+
|
|
621
|
+
Mix and match for precise control:
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
const ad = await client.decideFromContext({
|
|
625
|
+
userMessage: "I need car insurance",
|
|
626
|
+
// Phase 1: Quality & Brand Safety
|
|
627
|
+
minQualityScore: 0.8, // High quality only
|
|
628
|
+
allowedCategories: [31, 398], // Auto + Personal Finance Insurance (IAB)
|
|
629
|
+
// Phase 2: Revenue Optimization
|
|
630
|
+
minCPC: 50, // $0.50+ bids only
|
|
631
|
+
minRelevanceScore: 0.7, // Highly relevant only
|
|
632
|
+
optimizeFor: 'revenue' // Highest bid wins
|
|
633
|
+
});
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### HTTP Example
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
curl -X POST https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/decide \
|
|
640
|
+
-H "X-AM-API-Key: am_live_YOUR_KEY" \
|
|
641
|
+
-H "Content-Type: application/json" \
|
|
642
|
+
-d '{
|
|
643
|
+
"context": "I need car insurance",
|
|
644
|
+
"minQualityScore": 0.8,
|
|
645
|
+
"blockedCategories": ["crypto", "gambling"]
|
|
646
|
+
}'
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Best Practices
|
|
650
|
+
|
|
651
|
+
**Quality Scores:**
|
|
652
|
+
- Start with no filter, monitor what you get
|
|
653
|
+
- Gradually increase threshold if quality is lacking
|
|
654
|
+
- Higher thresholds = fewer ads but better quality
|
|
655
|
+
|
|
656
|
+
**Categories (IAB Taxonomy):**
|
|
657
|
+
- Use `getCategories()` to discover the full 704-category taxonomy
|
|
658
|
+
- Use `allowedCategories` for specialized apps (wedding planner = `[603]`, legal assistant = `[318]`)
|
|
659
|
+
- Use `blockedCategories` for compliance (kids apps = block `[601]` Sensitive Topics)
|
|
660
|
+
- Parent categories block all children automatically (block `[1]` Automotive = blocks all 40+ auto subcategories)
|
|
661
|
+
- Full taxonomy reference: https://github.com/InteractiveAdvertisingBureau/Taxonomies
|
|
662
|
+
|
|
663
|
+
**Advertiser Blocking:**
|
|
664
|
+
- Collect user feedback on specific ads
|
|
665
|
+
- Block advertisers with multiple complaints
|
|
666
|
+
- Use sparingly - too many blocks reduce fill rate
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
421
670
|
## API Reference
|
|
422
671
|
|
|
423
672
|
### `POST /v1/decide`
|
package/dist/index.d.mts
CHANGED
|
@@ -63,6 +63,68 @@ interface DecideFromContextRequest {
|
|
|
63
63
|
language?: string;
|
|
64
64
|
/** User's platform. Default: 'web' */
|
|
65
65
|
platform?: 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other';
|
|
66
|
+
/**
|
|
67
|
+
* Minimum quality score threshold (0.0 - 1.0).
|
|
68
|
+
* Only return ads with quality scores at or above this value.
|
|
69
|
+
* Higher values = better quality but lower fill rate.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* minQualityScore: 0.8 // Only show ads with 0.8+ quality
|
|
73
|
+
*/
|
|
74
|
+
minQualityScore?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Only show ads from these categories.
|
|
77
|
+
* If set, blockedCategories is ignored.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* allowedCategories: ['wedding', 'photography', 'venues']
|
|
81
|
+
*/
|
|
82
|
+
allowedCategories?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Never show ads from these categories.
|
|
85
|
+
* Ignored if allowedCategories is set.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* blockedCategories: ['gambling', 'crypto', 'dating']
|
|
89
|
+
*/
|
|
90
|
+
blockedCategories?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Never show ads from these advertisers.
|
|
93
|
+
* Use advertiser IDs from previous ad responses.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* blockedAdvertisers: ['adv_abc123', 'adv_xyz789']
|
|
97
|
+
*/
|
|
98
|
+
blockedAdvertisers?: string[];
|
|
99
|
+
/**
|
|
100
|
+
* Minimum cost-per-click threshold in cents.
|
|
101
|
+
* Only return ads with bids at or above this value.
|
|
102
|
+
* Higher values = more revenue per ad but lower fill rate.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* minCPC: 50 // Only show ads bidding $0.50 or more per click
|
|
106
|
+
*/
|
|
107
|
+
minCPC?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Minimum semantic relevance score threshold (0.0 - 1.0).
|
|
110
|
+
* Only return ads with relevance scores at or above this value.
|
|
111
|
+
* Higher values = more relevant ads but lower fill rate.
|
|
112
|
+
* Default backend threshold: 0.25
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* minRelevanceScore: 0.8 // Only show highly relevant ads
|
|
116
|
+
*/
|
|
117
|
+
minRelevanceScore?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Ad ranking strategy.
|
|
120
|
+
* - 'revenue': Rank by bid amount (highest bid wins)
|
|
121
|
+
* - 'relevance': Rank by semantic similarity (best match wins)
|
|
122
|
+
* Default: 'revenue'
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* optimizeFor: 'relevance' // Prioritize best semantic match over highest bid
|
|
126
|
+
*/
|
|
127
|
+
optimizeFor?: 'revenue' | 'relevance';
|
|
66
128
|
}
|
|
67
129
|
interface DecideResponse {
|
|
68
130
|
request_id: string;
|
|
@@ -557,6 +619,44 @@ interface GetServiceRequest {
|
|
|
557
619
|
region?: string;
|
|
558
620
|
};
|
|
559
621
|
}
|
|
622
|
+
interface IABCategory {
|
|
623
|
+
/** Unique IAB category ID */
|
|
624
|
+
id: number;
|
|
625
|
+
/** Parent category ID (null for tier 1 categories) */
|
|
626
|
+
parent_id: number | null;
|
|
627
|
+
/** Category name */
|
|
628
|
+
name: string;
|
|
629
|
+
/** Tier 1 category (top level) */
|
|
630
|
+
tier_1: string | null;
|
|
631
|
+
/** Tier 2 category (sub-category) */
|
|
632
|
+
tier_2: string | null;
|
|
633
|
+
/** Tier 3 category (sub-sub-category) */
|
|
634
|
+
tier_3: string | null;
|
|
635
|
+
/** Tier 4 category (deepest level) */
|
|
636
|
+
tier_4: string | null;
|
|
637
|
+
/** Full hierarchical path (e.g., "Automotive > Auto Insurance") */
|
|
638
|
+
full_path: string;
|
|
639
|
+
}
|
|
640
|
+
interface CategoryTaxonomyResponse {
|
|
641
|
+
/** Taxonomy version */
|
|
642
|
+
version: string;
|
|
643
|
+
/** Source organization */
|
|
644
|
+
source: string;
|
|
645
|
+
/** Reference URL */
|
|
646
|
+
url: string;
|
|
647
|
+
/** Total number of categories returned (after filtering) */
|
|
648
|
+
total: number;
|
|
649
|
+
/** Array of categories */
|
|
650
|
+
categories: IABCategory[];
|
|
651
|
+
}
|
|
652
|
+
interface GetCategoriesParams {
|
|
653
|
+
/** Filter by tier level (1-4) */
|
|
654
|
+
tier?: 1 | 2 | 3 | 4;
|
|
655
|
+
/** Filter by parent category ID */
|
|
656
|
+
parent_id?: number;
|
|
657
|
+
/** Search by name or path (case-insensitive) */
|
|
658
|
+
search?: string;
|
|
659
|
+
}
|
|
560
660
|
|
|
561
661
|
/**
|
|
562
662
|
* Utility functions for the AttentionMarket SDK.
|
|
@@ -989,6 +1089,39 @@ declare class AttentionMarketClient {
|
|
|
989
1089
|
* ```
|
|
990
1090
|
*/
|
|
991
1091
|
logServiceResult(params: ServiceResultRequest): Promise<ServiceResultResponse>;
|
|
1092
|
+
/**
|
|
1093
|
+
* Get IAB Content Taxonomy categories.
|
|
1094
|
+
*
|
|
1095
|
+
* Returns the complete IAB Content Taxonomy 3.0 (704 categories across 38 top-level categories).
|
|
1096
|
+
* Supports filtering by tier level, parent category, or search term.
|
|
1097
|
+
*
|
|
1098
|
+
* Use this to discover available categories for `allowedCategories` and `blockedCategories` parameters.
|
|
1099
|
+
*
|
|
1100
|
+
* @param params - Optional filters (tier, parent_id, search)
|
|
1101
|
+
* @returns The IAB Content Taxonomy with categories
|
|
1102
|
+
*
|
|
1103
|
+
* @example Get all Tier 1 categories (38 top-level categories)
|
|
1104
|
+
* ```typescript
|
|
1105
|
+
* const tier1 = await client.getCategories({ tier: 1 });
|
|
1106
|
+
* console.log(`${tier1.total} top-level categories`);
|
|
1107
|
+
* tier1.categories.forEach(cat => console.log(`${cat.id}: ${cat.name}`));
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* @example Get all subcategories of "Automotive" (ID: 1)
|
|
1111
|
+
* ```typescript
|
|
1112
|
+
* const automotiveCategories = await client.getCategories({ parent_id: 1 });
|
|
1113
|
+
* console.log(`Found ${automotiveCategories.total} automotive subcategories`);
|
|
1114
|
+
* ```
|
|
1115
|
+
*
|
|
1116
|
+
* @example Search for insurance-related categories
|
|
1117
|
+
* ```typescript
|
|
1118
|
+
* const insuranceCategories = await client.getCategories({ search: 'insurance' });
|
|
1119
|
+
* insuranceCategories.categories.forEach(cat => {
|
|
1120
|
+
* console.log(`${cat.id}: ${cat.full_path}`);
|
|
1121
|
+
* });
|
|
1122
|
+
* ```
|
|
1123
|
+
*/
|
|
1124
|
+
getCategories(params?: GetCategoriesParams): Promise<CategoryTaxonomyResponse>;
|
|
992
1125
|
}
|
|
993
1126
|
|
|
994
1127
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -63,6 +63,68 @@ interface DecideFromContextRequest {
|
|
|
63
63
|
language?: string;
|
|
64
64
|
/** User's platform. Default: 'web' */
|
|
65
65
|
platform?: 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other';
|
|
66
|
+
/**
|
|
67
|
+
* Minimum quality score threshold (0.0 - 1.0).
|
|
68
|
+
* Only return ads with quality scores at or above this value.
|
|
69
|
+
* Higher values = better quality but lower fill rate.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* minQualityScore: 0.8 // Only show ads with 0.8+ quality
|
|
73
|
+
*/
|
|
74
|
+
minQualityScore?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Only show ads from these categories.
|
|
77
|
+
* If set, blockedCategories is ignored.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* allowedCategories: ['wedding', 'photography', 'venues']
|
|
81
|
+
*/
|
|
82
|
+
allowedCategories?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Never show ads from these categories.
|
|
85
|
+
* Ignored if allowedCategories is set.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* blockedCategories: ['gambling', 'crypto', 'dating']
|
|
89
|
+
*/
|
|
90
|
+
blockedCategories?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Never show ads from these advertisers.
|
|
93
|
+
* Use advertiser IDs from previous ad responses.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* blockedAdvertisers: ['adv_abc123', 'adv_xyz789']
|
|
97
|
+
*/
|
|
98
|
+
blockedAdvertisers?: string[];
|
|
99
|
+
/**
|
|
100
|
+
* Minimum cost-per-click threshold in cents.
|
|
101
|
+
* Only return ads with bids at or above this value.
|
|
102
|
+
* Higher values = more revenue per ad but lower fill rate.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* minCPC: 50 // Only show ads bidding $0.50 or more per click
|
|
106
|
+
*/
|
|
107
|
+
minCPC?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Minimum semantic relevance score threshold (0.0 - 1.0).
|
|
110
|
+
* Only return ads with relevance scores at or above this value.
|
|
111
|
+
* Higher values = more relevant ads but lower fill rate.
|
|
112
|
+
* Default backend threshold: 0.25
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* minRelevanceScore: 0.8 // Only show highly relevant ads
|
|
116
|
+
*/
|
|
117
|
+
minRelevanceScore?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Ad ranking strategy.
|
|
120
|
+
* - 'revenue': Rank by bid amount (highest bid wins)
|
|
121
|
+
* - 'relevance': Rank by semantic similarity (best match wins)
|
|
122
|
+
* Default: 'revenue'
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* optimizeFor: 'relevance' // Prioritize best semantic match over highest bid
|
|
126
|
+
*/
|
|
127
|
+
optimizeFor?: 'revenue' | 'relevance';
|
|
66
128
|
}
|
|
67
129
|
interface DecideResponse {
|
|
68
130
|
request_id: string;
|
|
@@ -557,6 +619,44 @@ interface GetServiceRequest {
|
|
|
557
619
|
region?: string;
|
|
558
620
|
};
|
|
559
621
|
}
|
|
622
|
+
interface IABCategory {
|
|
623
|
+
/** Unique IAB category ID */
|
|
624
|
+
id: number;
|
|
625
|
+
/** Parent category ID (null for tier 1 categories) */
|
|
626
|
+
parent_id: number | null;
|
|
627
|
+
/** Category name */
|
|
628
|
+
name: string;
|
|
629
|
+
/** Tier 1 category (top level) */
|
|
630
|
+
tier_1: string | null;
|
|
631
|
+
/** Tier 2 category (sub-category) */
|
|
632
|
+
tier_2: string | null;
|
|
633
|
+
/** Tier 3 category (sub-sub-category) */
|
|
634
|
+
tier_3: string | null;
|
|
635
|
+
/** Tier 4 category (deepest level) */
|
|
636
|
+
tier_4: string | null;
|
|
637
|
+
/** Full hierarchical path (e.g., "Automotive > Auto Insurance") */
|
|
638
|
+
full_path: string;
|
|
639
|
+
}
|
|
640
|
+
interface CategoryTaxonomyResponse {
|
|
641
|
+
/** Taxonomy version */
|
|
642
|
+
version: string;
|
|
643
|
+
/** Source organization */
|
|
644
|
+
source: string;
|
|
645
|
+
/** Reference URL */
|
|
646
|
+
url: string;
|
|
647
|
+
/** Total number of categories returned (after filtering) */
|
|
648
|
+
total: number;
|
|
649
|
+
/** Array of categories */
|
|
650
|
+
categories: IABCategory[];
|
|
651
|
+
}
|
|
652
|
+
interface GetCategoriesParams {
|
|
653
|
+
/** Filter by tier level (1-4) */
|
|
654
|
+
tier?: 1 | 2 | 3 | 4;
|
|
655
|
+
/** Filter by parent category ID */
|
|
656
|
+
parent_id?: number;
|
|
657
|
+
/** Search by name or path (case-insensitive) */
|
|
658
|
+
search?: string;
|
|
659
|
+
}
|
|
560
660
|
|
|
561
661
|
/**
|
|
562
662
|
* Utility functions for the AttentionMarket SDK.
|
|
@@ -989,6 +1089,39 @@ declare class AttentionMarketClient {
|
|
|
989
1089
|
* ```
|
|
990
1090
|
*/
|
|
991
1091
|
logServiceResult(params: ServiceResultRequest): Promise<ServiceResultResponse>;
|
|
1092
|
+
/**
|
|
1093
|
+
* Get IAB Content Taxonomy categories.
|
|
1094
|
+
*
|
|
1095
|
+
* Returns the complete IAB Content Taxonomy 3.0 (704 categories across 38 top-level categories).
|
|
1096
|
+
* Supports filtering by tier level, parent category, or search term.
|
|
1097
|
+
*
|
|
1098
|
+
* Use this to discover available categories for `allowedCategories` and `blockedCategories` parameters.
|
|
1099
|
+
*
|
|
1100
|
+
* @param params - Optional filters (tier, parent_id, search)
|
|
1101
|
+
* @returns The IAB Content Taxonomy with categories
|
|
1102
|
+
*
|
|
1103
|
+
* @example Get all Tier 1 categories (38 top-level categories)
|
|
1104
|
+
* ```typescript
|
|
1105
|
+
* const tier1 = await client.getCategories({ tier: 1 });
|
|
1106
|
+
* console.log(`${tier1.total} top-level categories`);
|
|
1107
|
+
* tier1.categories.forEach(cat => console.log(`${cat.id}: ${cat.name}`));
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* @example Get all subcategories of "Automotive" (ID: 1)
|
|
1111
|
+
* ```typescript
|
|
1112
|
+
* const automotiveCategories = await client.getCategories({ parent_id: 1 });
|
|
1113
|
+
* console.log(`Found ${automotiveCategories.total} automotive subcategories`);
|
|
1114
|
+
* ```
|
|
1115
|
+
*
|
|
1116
|
+
* @example Search for insurance-related categories
|
|
1117
|
+
* ```typescript
|
|
1118
|
+
* const insuranceCategories = await client.getCategories({ search: 'insurance' });
|
|
1119
|
+
* insuranceCategories.categories.forEach(cat => {
|
|
1120
|
+
* console.log(`${cat.id}: ${cat.full_path}`);
|
|
1121
|
+
* });
|
|
1122
|
+
* ```
|
|
1123
|
+
*/
|
|
1124
|
+
getCategories(params?: GetCategoriesParams): Promise<CategoryTaxonomyResponse>;
|
|
992
1125
|
}
|
|
993
1126
|
|
|
994
1127
|
/**
|
package/dist/index.js
CHANGED
|
@@ -503,6 +503,60 @@ var AttentionMarketClient = class {
|
|
|
503
503
|
const platform = params.platform || "web";
|
|
504
504
|
const placementType = params.placement || "sponsored_suggestion";
|
|
505
505
|
const taxonomy = params.suggestedCategory || this.inferTaxonomy(params.userMessage);
|
|
506
|
+
if (params.minQualityScore !== void 0) {
|
|
507
|
+
if (typeof params.minQualityScore !== "number" || params.minQualityScore < 0 || params.minQualityScore > 1) {
|
|
508
|
+
throw new Error("minQualityScore must be a number between 0.0 and 1.0");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (params.allowedCategories !== void 0) {
|
|
512
|
+
if (!Array.isArray(params.allowedCategories)) {
|
|
513
|
+
throw new Error("allowedCategories must be an array");
|
|
514
|
+
}
|
|
515
|
+
if (params.allowedCategories.length === 0) {
|
|
516
|
+
throw new Error("allowedCategories cannot be empty (would block all ads). Use blockedCategories to exclude specific categories, or omit to allow all.");
|
|
517
|
+
}
|
|
518
|
+
for (const cat of params.allowedCategories) {
|
|
519
|
+
if (typeof cat !== "string" && typeof cat !== "number") {
|
|
520
|
+
throw new Error(`allowedCategories must contain strings or numbers, found: ${typeof cat}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (params.blockedCategories !== void 0) {
|
|
525
|
+
if (!Array.isArray(params.blockedCategories)) {
|
|
526
|
+
throw new Error("blockedCategories must be an array");
|
|
527
|
+
}
|
|
528
|
+
for (const cat of params.blockedCategories) {
|
|
529
|
+
if (typeof cat !== "string" && typeof cat !== "number") {
|
|
530
|
+
throw new Error(`blockedCategories must contain strings or numbers, found: ${typeof cat}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (params.allowedCategories && params.allowedCategories.length > 0) {
|
|
534
|
+
console.warn("[AttentionMarket] Both allowedCategories and blockedCategories specified. blockedCategories will be ignored.");
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (params.blockedAdvertisers !== void 0) {
|
|
538
|
+
if (!Array.isArray(params.blockedAdvertisers)) {
|
|
539
|
+
throw new Error("blockedAdvertisers must be an array");
|
|
540
|
+
}
|
|
541
|
+
for (const id of params.blockedAdvertisers) {
|
|
542
|
+
if (typeof id !== "string" || id.trim().length === 0) {
|
|
543
|
+
throw new Error("blockedAdvertisers must contain non-empty strings (advertiser IDs)");
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (params.minCPC !== void 0) {
|
|
548
|
+
if (typeof params.minCPC !== "number" || params.minCPC < 0) {
|
|
549
|
+
throw new Error("minCPC must be a non-negative number (cost-per-click in cents)");
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (params.minRelevanceScore !== void 0) {
|
|
553
|
+
if (typeof params.minRelevanceScore !== "number" || params.minRelevanceScore < 0 || params.minRelevanceScore > 1) {
|
|
554
|
+
throw new Error("minRelevanceScore must be a number between 0.0 and 1.0");
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (params.optimizeFor && params.optimizeFor !== "revenue" && params.optimizeFor !== "relevance") {
|
|
558
|
+
throw new Error('optimizeFor must be either "revenue" or "relevance"');
|
|
559
|
+
}
|
|
506
560
|
const request = {
|
|
507
561
|
request_id: generateUUID(),
|
|
508
562
|
agent_id: this.agentId,
|
|
@@ -529,7 +583,16 @@ var AttentionMarketClient = class {
|
|
|
529
583
|
}
|
|
530
584
|
},
|
|
531
585
|
context,
|
|
532
|
-
user_intent: params.userMessage
|
|
586
|
+
user_intent: params.userMessage,
|
|
587
|
+
// Developer controls (Phase 1: Quality & Brand Safety)
|
|
588
|
+
...params.minQualityScore !== void 0 && { minQualityScore: params.minQualityScore },
|
|
589
|
+
...params.allowedCategories && { allowedCategories: params.allowedCategories },
|
|
590
|
+
...params.blockedCategories && { blockedCategories: params.blockedCategories },
|
|
591
|
+
...params.blockedAdvertisers && { blockedAdvertisers: params.blockedAdvertisers },
|
|
592
|
+
// Developer controls (Phase 2: Revenue Optimization)
|
|
593
|
+
...params.minCPC !== void 0 && { minCPC: params.minCPC },
|
|
594
|
+
...params.minRelevanceScore !== void 0 && { minRelevanceScore: params.minRelevanceScore },
|
|
595
|
+
...params.optimizeFor && { optimizeFor: params.optimizeFor }
|
|
533
596
|
};
|
|
534
597
|
const response = await this.decideRaw(request, options);
|
|
535
598
|
if (response.status === "no_fill" || response.units.length === 0) {
|
|
@@ -1156,6 +1219,55 @@ var AttentionMarketClient = class {
|
|
|
1156
1219
|
{ body: params }
|
|
1157
1220
|
);
|
|
1158
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Get IAB Content Taxonomy categories.
|
|
1224
|
+
*
|
|
1225
|
+
* Returns the complete IAB Content Taxonomy 3.0 (704 categories across 38 top-level categories).
|
|
1226
|
+
* Supports filtering by tier level, parent category, or search term.
|
|
1227
|
+
*
|
|
1228
|
+
* Use this to discover available categories for `allowedCategories` and `blockedCategories` parameters.
|
|
1229
|
+
*
|
|
1230
|
+
* @param params - Optional filters (tier, parent_id, search)
|
|
1231
|
+
* @returns The IAB Content Taxonomy with categories
|
|
1232
|
+
*
|
|
1233
|
+
* @example Get all Tier 1 categories (38 top-level categories)
|
|
1234
|
+
* ```typescript
|
|
1235
|
+
* const tier1 = await client.getCategories({ tier: 1 });
|
|
1236
|
+
* console.log(`${tier1.total} top-level categories`);
|
|
1237
|
+
* tier1.categories.forEach(cat => console.log(`${cat.id}: ${cat.name}`));
|
|
1238
|
+
* ```
|
|
1239
|
+
*
|
|
1240
|
+
* @example Get all subcategories of "Automotive" (ID: 1)
|
|
1241
|
+
* ```typescript
|
|
1242
|
+
* const automotiveCategories = await client.getCategories({ parent_id: 1 });
|
|
1243
|
+
* console.log(`Found ${automotiveCategories.total} automotive subcategories`);
|
|
1244
|
+
* ```
|
|
1245
|
+
*
|
|
1246
|
+
* @example Search for insurance-related categories
|
|
1247
|
+
* ```typescript
|
|
1248
|
+
* const insuranceCategories = await client.getCategories({ search: 'insurance' });
|
|
1249
|
+
* insuranceCategories.categories.forEach(cat => {
|
|
1250
|
+
* console.log(`${cat.id}: ${cat.full_path}`);
|
|
1251
|
+
* });
|
|
1252
|
+
* ```
|
|
1253
|
+
*/
|
|
1254
|
+
async getCategories(params) {
|
|
1255
|
+
const queryParams = new URLSearchParams();
|
|
1256
|
+
if (params?.tier) {
|
|
1257
|
+
queryParams.append("tier", params.tier.toString());
|
|
1258
|
+
}
|
|
1259
|
+
if (params?.parent_id) {
|
|
1260
|
+
queryParams.append("parent_id", params.parent_id.toString());
|
|
1261
|
+
}
|
|
1262
|
+
if (params?.search) {
|
|
1263
|
+
queryParams.append("search", params.search);
|
|
1264
|
+
}
|
|
1265
|
+
const url = `/v1/categories${queryParams.toString() ? "?" + queryParams.toString() : ""}`;
|
|
1266
|
+
return await this.http.request(
|
|
1267
|
+
"GET",
|
|
1268
|
+
url
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1159
1271
|
};
|
|
1160
1272
|
|
|
1161
1273
|
// src/mock-client.ts
|