@the_ro_show/agent-ads-sdk 0.4.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,22 +4,21 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- **The first ad network built for AI agents.** Monetize your AI agent with contextual, high-intent sponsored suggestions. Open source, transparent, developer-first.
7
+ Ad network for AI agents. Pass user messages, get contextually relevant ads, earn revenue. Similar to AdSense but designed for conversational interfaces. It's time to start monetizing your AI agents!
8
8
 
9
- - 🚀 **5-minute integration** - npm install + 5 lines of code
10
- - 💰 **70% revenue share** - You keep the majority, we only win when you do
11
- - 🎯 **10-15% CTR** - High-intent placements, not banner ads
12
- - 🔓 **100% Open Source** - Audit every line, full transparency
9
+ - **70% revenue share** - You keep most of the earnings (I use the remaining 30% to onboard advertisers and support that ecosystem).
10
+ - **Simple integration** - One API call to get ads
13
11
 
14
- ## Quick Start
12
+ ---
15
13
 
16
- ### 1. Get Your API Key
14
+ ## Quick Start
17
15
 
18
- **Sign up at [attentionmarket.com/signup](https://attentionmarket.com/signup)** (30 seconds, free forever)
16
+ ### 1. Get API Key
19
17
 
20
- You'll receive:
21
- - Test key: `am_test_...` (for development)
22
- - Live key: `am_live_...` (for production)
18
+ Sign up at [attentionmarket.com/signup](https://api.attentionmarket.ai/) to receive:
19
+ - Test key: `am_test_...`
20
+ - Live key: `am_live_...`
21
+ - Agent ID
23
22
 
24
23
  ### 2. Install
25
24
 
@@ -27,295 +26,347 @@ You'll receive:
27
26
  npm install @the_ro_show/agent-ads-sdk
28
27
  ```
29
28
 
30
- ### 3. Integrate (5 lines of code)
29
+ ### 3. Basic Usage
31
30
 
32
31
  ```typescript
33
- import { AttentionMarketClient, detectIntent, buildTaxonomy } from '@the_ro_show/agent-ads-sdk';
32
+ import { AttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
34
33
 
35
34
  const client = new AttentionMarketClient({
36
- apiKey: process.env.ATTENTIONMARKET_API_KEY // Your test or live key
35
+ apiKey: process.env.ATTENTIONMARKET_API_KEY,
36
+ agentId: 'your_agent_id'
37
37
  });
38
38
 
39
- // When your agent helps users, show relevant ads
40
- const userQuery = "I need car insurance for my Honda";
41
- const intent = detectIntent(userQuery); // "quote" or "compare" or "research"
42
- const taxonomy = buildTaxonomy('insurance', 'auto', 'full_coverage', intent);
43
-
44
- const decision = await client.decide({
45
- request_id: crypto.randomUUID(),
46
- agent_id: 'your_agent_id',
47
- placement: { type: 'sponsored_suggestion' },
48
- opportunity: {
49
- intent: { taxonomy }, // "insurance.auto.full_coverage.quote"
50
- context: { country: 'US', language: 'en', platform: 'web' }
51
- }
39
+ // Request an ad based on user message
40
+ const ad = await client.decideFromContext({
41
+ userMessage: "I need car insurance"
52
42
  });
53
43
 
54
- if (decision.status === 'filled') {
55
- const ad = decision.units[0];
56
- console.log(`[Sponsored] ${ad.suggestion.title}`);
57
- // User clicks → You earn $5-50
44
+ if (ad) {
45
+ console.log(ad.creative.title);
46
+ console.log(ad.creative.body);
47
+ console.log(ad.creative.cta);
58
48
  }
59
49
  ```
60
50
 
61
- **That's it!** Start earning from relevant ads.
62
-
63
51
  ---
64
52
 
65
- ## 🆕 What's New in v0.4.0
53
+ ## How It Works
54
+
55
+ 1. User interacts with your agent: `"I need help with estate planning"`
56
+ 2. You pass the message to `decideFromContext()`
57
+ 3. We return a matching ad from our network
58
+ 4. You display it and track clicks to earn revenue
66
59
 
67
- ### Hierarchical Taxonomy Matching
60
+ The API handles intent detection and ad matching automatically.
68
61
 
69
- Target broadly, match specifically:
62
+ ---
63
+
64
+ ## Complete Example
65
+
66
+ Full integration including ad retrieval, display, and click tracking:
70
67
 
71
68
  ```typescript
72
- // Advertiser targets: "insurance.auto"
73
- // Your agent requests: "insurance.auto.full_coverage.quote"
74
- // ✅ Matches! (0.7 relevance score)
69
+ import { AttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
75
70
 
76
- // Your agent requests: "insurance.auto.liability.compare"
77
- // ✅ Also matches! (0.7 relevance score)
71
+ const client = new AttentionMarketClient({
72
+ apiKey: process.env.ATTENTIONMARKET_API_KEY,
73
+ agentId: 'your_agent_id'
74
+ });
78
75
 
79
- // Your agent requests: "insurance.home.flood.quote"
80
- // No match (different category)
81
- ```
76
+ async function handleUserMessage(userMessage: string) {
77
+ const ad = await client.decideFromContext({ userMessage });
82
78
 
83
- **Result:** 3x more ad inventory, higher fill rates.
79
+ if (!ad) {
80
+ return null; // No ads available
81
+ }
84
82
 
85
- ### New Helper Functions
83
+ // Display ad (you can customize this)
84
+ const displayMessage = `\n[Sponsored] ${ad.disclosure.sponsor_name}\n${ad.creative.title}\n${ad.creative.body}\n${ad.creative.cta}\n`;
85
+ console.log(displayMessage);
86
86
 
87
- **Auto-detect user intent:**
88
- ```typescript
89
- import { detectIntent } from '@the_ro_show/agent-ads-sdk';
87
+ // Track click when user clicks
88
+ await client.trackClick({
89
+ agent_id: 'your_agent_id',
90
+ request_id: ad.request_id,
91
+ decision_id: ad.offer_id,
92
+ unit_id: ad.offer_id,
93
+ tracking_token: ad.tracking_token,
94
+ href: ad.click_url,
95
+ click_context: displayMessage // What was actually shown to user
96
+ });
90
97
 
91
- detectIntent("What is car insurance?") // → 'research'
92
- detectIntent("Compare car insurance options") // → 'compare'
93
- detectIntent("Get car insurance quote") // → 'quote'
94
- detectIntent("I want to buy car insurance") // → 'apply'
98
+ return ad;
99
+ }
95
100
  ```
96
101
 
97
- **Build taxonomies easily:**
98
- ```typescript
99
- import { buildTaxonomy } from '@the_ro_show/agent-ads-sdk';
102
+ ---
100
103
 
101
- const taxonomy = buildTaxonomy('insurance', 'auto', 'full_coverage', 'quote');
102
- // → "insurance.auto.full_coverage.quote"
103
- ```
104
+ ## API Reference
104
105
 
105
- **Get taxonomy suggestions:**
106
- ```typescript
107
- import { suggestTaxonomies } from '@the_ro_show/agent-ads-sdk';
106
+ ### Primary API
108
107
 
109
- const suggestions = suggestTaxonomies("I need a lawyer for divorce");
110
- // → ['legal.family.divorce.consultation', 'legal.family.custody.consultation']
111
- ```
108
+ #### `decideFromContext(params)` `Promise <OfferResponse | null>`
109
+
110
+ Pass a user message and optionally conversation history. Returns a matching ad or null if no fill.
112
111
 
113
- **Validate taxonomies:**
114
112
  ```typescript
115
- import { isValidTaxonomy, parseTaxonomy } from '@the_ro_show/agent-ads-sdk';
113
+ const ad = await client.decideFromContext({
114
+ userMessage: "I need help with estate planning",
115
+ conversationHistory: ["My father passed away recently"], // Optional
116
+ context: { geo: { city: 'NYC', country: 'US' } } // Optional
117
+ });
118
+ ```
116
119
 
117
- isValidTaxonomy('insurance.auto.full_coverage.quote') // true
118
- isValidTaxonomy('invalid.format') // false
120
+ Returns ad with:
121
+ - `creative.title` - Ad headline
122
+ - `creative.body` - Ad description
123
+ - `creative.cta` - Call to action
124
+ - `click_url` - URL to open on click
125
+ - `tracking_token` - Required for revenue tracking
126
+ - `disclosure` - Sponsor information
119
127
 
120
- const parsed = parseTaxonomy('insurance.auto.full_coverage.quote');
121
- // → { vertical: 'insurance', category: 'auto', subcategory: 'full_coverage', intent: 'quote' }
122
- ```
128
+ ### Revenue Tracking
123
129
 
124
- ---
130
+ #### `trackClick(params)` → `Promise<void>`
125
131
 
126
- ## Common Taxonomies
132
+ Records user clicks for revenue attribution. Call this when a user clicks an ad. Handles deduplication and retries automatically.
127
133
 
128
- ### Insurance ($20-54 CPC)
129
- ```typescript
130
- 'insurance.auto.full_coverage.quote'
131
- 'insurance.auto.liability.compare'
132
- 'insurance.home.standard.quote'
133
- 'insurance.life.term.compare'
134
- 'insurance.health.individual.quote'
135
- ```
134
+ **Required:** `click_context` - The actual message shown to the user. This helps optimize ad creative based on what converts.
136
135
 
137
- ### Legal ($50-150 CPC)
138
136
  ```typescript
139
- 'legal.personal_injury.accident.consultation'
140
- 'legal.family.divorce.consultation'
141
- 'legal.criminal.defense.consultation'
142
- 'legal.immigration.visa.consultation'
143
- 'legal.estate_planning.will.consultation'
137
+ await client.trackClick({
138
+ agent_id: 'your_agent_id',
139
+ request_id: ad.request_id,
140
+ decision_id: ad.offer_id,
141
+ unit_id: ad.offer_id,
142
+ tracking_token: ad.tracking_token,
143
+ href: ad.click_url,
144
+ click_context: "The message shown to user that they clicked"
145
+ });
144
146
  ```
145
147
 
146
- ### Financial Services ($15-50 CPC)
147
- ```typescript
148
- 'financial.loans.personal.quote'
149
- 'financial.loans.mortgage.compare'
150
- 'financial.credit_cards.rewards.compare'
151
- 'financial.investing.brokerage.trial'
152
- ```
148
+ ### Testing
149
+
150
+ #### `MockAttentionMarketClient`
151
+
152
+ Mock client for testing without API calls. Simulates latency and fill rate behavior.
153
153
 
154
- ### B2B SaaS ($10-100 CPC)
155
154
  ```typescript
156
- 'business.saas.crm.trial'
157
- 'business.saas.project_management.trial'
158
- 'business.ecommerce.platform.trial'
159
- 'business.saas.marketing_automation.trial'
155
+ import { MockAttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
156
+
157
+ const client = new MockAttentionMarketClient({
158
+ fillRate: 1.0, // Always return ads (0.0 = never, 0.5 = 50% of time)
159
+ latencyMs: 100, // Simulate API latency
160
+ verbose: true // Log what's happening
161
+ });
162
+
163
+ // Works exactly like the real client
164
+ const ad = await client.decideFromContext({ userMessage: "test" });
160
165
  ```
161
166
 
162
- ### Home Services ($5-30 CPC)
167
+ ---
168
+
169
+ ## Advanced Features
170
+
171
+ <details>
172
+ <summary><strong>Click to view advanced APIs (most developers don't need these)</strong></summary>
173
+
174
+ <br>
175
+
176
+ The simple `decideFromContext()` API handles everything for 90% of use cases. But if you need more control:
177
+
178
+ ### Manual Category Targeting
179
+
180
+ #### `decide()` - Specify exact categories
181
+ When you know the exact category, use manual taxonomy matching for deterministic results.
182
+
163
183
  ```typescript
164
- 'home_services.moving.local.quote'
165
- 'home_services.cleaning.regular.book'
166
- 'home_services.plumbing.emergency.quote'
167
- 'home_services.remodeling.kitchen.quote'
184
+ const decision = await client.decide({
185
+ request_id: crypto.randomUUID(),
186
+ agent_id: 'your_agent_id',
187
+ placement: { type: 'sponsored_suggestion' },
188
+ opportunity: {
189
+ intent: { taxonomy: 'insurance.auto.full_coverage.quote' },
190
+ context: { country: 'US', language: 'en', platform: 'web' }
191
+ }
192
+ });
168
193
  ```
169
194
 
170
- **See all 50+ taxonomies:** [TAXONOMY_SYSTEM.md](./TAXONOMY_SYSTEM.md)
195
+ See [TAXONOMY_SYSTEM.md](./TAXONOMY_SYSTEM.md) for all categories.
171
196
 
172
197
  ---
173
198
 
174
- ## Complete Example
199
+ ### 🌐 Intenture Network APIs (Agent-to-Agent)
200
+
201
+ #### `requestOffer()` - Intent-key based matching for high confidence scenarios
202
+ When you KNOW what the user wants (they said "order coffee" or "book lawyer"), use intent-keys like `coffee.purchase.delivery` for deterministic matching. Enables agent-to-agent coordination and revenue sharing.
175
203
 
176
204
  ```typescript
177
- import {
178
- AttentionMarketClient,
179
- buildTaxonomy,
180
- detectIntent
181
- } from '@the_ro_show/agent-ads-sdk';
205
+ const offer = await client.requestOffer({
206
+ placementId: 'order_card',
207
+ intentKey: 'coffee.purchase.delivery',
208
+ context: { geo: { city: 'SF', country: 'US' } }
209
+ });
210
+ ```
182
211
 
183
- const client = new AttentionMarketClient({
184
- apiKey: process.env.ATTENTIONMARKET_API_KEY
212
+ #### `requestOfferFromContext()` - Semantic discovery for fuzzy intents
213
+ When you're NOT sure what they need (they said "I'm so tired"), pass the conversation and let semantic search find relevant offers. Auto-limits history to last 5 messages.
214
+
215
+ ```typescript
216
+ const offer = await client.requestOfferFromContext({
217
+ placementId: 'chat_suggestion',
218
+ userMessage: "I'm so tired, long day at work...",
219
+ conversationHistory: ["How was your day?", "Exhausting"],
220
+ context: { geo: { city: 'NYC' } }
185
221
  });
222
+ ```
186
223
 
187
- async function showRelevantAd(userQuery: string) {
188
- // 1. Detect what the user wants
189
- const intent = detectIntent(userQuery);
190
-
191
- // 2. Build taxonomy (or use your own logic)
192
- let taxonomy: string;
193
- if (/insurance|car|auto/i.test(userQuery)) {
194
- taxonomy = buildTaxonomy('insurance', 'auto', 'full_coverage', intent);
195
- } else if (/lawyer|legal|divorce/i.test(userQuery)) {
196
- taxonomy = buildTaxonomy('legal', 'family', 'divorce', 'consultation');
197
- } else {
198
- return null; // No relevant ads
199
- }
224
+ #### Revenue Share (Preview) - Track referrals between agents
225
+ If another agent sends users to you, include their agent_id to split revenue (0-50%). Currently in preview mode (logs only) - payouts activate Q2 2026. Think affiliate marketing for AI agents.
200
226
 
201
- // 3. Request ads
202
- const decision = await client.decide({
203
- request_id: crypto.randomUUID(),
204
- agent_id: 'your_agent_id',
205
- placement: { type: 'sponsored_suggestion' },
206
- opportunity: {
207
- intent: { taxonomy },
208
- context: {
209
- country: 'US',
210
- language: 'en',
211
- platform: 'web'
212
- }
213
- }
214
- });
227
+ ```typescript
228
+ const offer = await client.requestOffer({
229
+ intentKey: 'legal.divorce.consultation',
230
+ sourceAgentId: 'agt_referrer_123', // Agent who sent the user
231
+ revenueSharePct: 30, // Give them 30% of revenue
232
+ // ... other params
233
+ });
234
+ ```
215
235
 
216
- // 4. Show ad if available
217
- if (decision.status === 'filled') {
218
- const ad = decision.units[0];
236
+ ---
219
237
 
220
- console.log(`\n[${ad.disclosure.label}] ${ad.disclosure.sponsor_name}`);
221
- console.log(ad.suggestion.title);
222
- console.log(ad.suggestion.body);
223
- console.log(`→ ${ad.suggestion.cta}\n`);
238
+ ### 🧠 Intent Detection
224
239
 
225
- // 5. Track impression (for billing)
226
- await client.trackImpression({
227
- agent_id: 'your_agent_id',
228
- request_id: decision.request_id,
229
- decision_id: decision.decision_id,
230
- unit_id: ad.unit_id,
231
- tracking_token: ad.tracking.token
232
- });
240
+ #### `detectIntent()` - Auto-detect where users are in their journey
241
+ Analyzes queries to determine if they're researching ("what is X?"), comparing ("X vs Y"), getting quotes ("how much?"), or ready to buy ("I want X"). Returns 'research', 'compare', 'quote', 'apply', 'support', or 'other'.
233
242
 
234
- // 6. Track click when user clicks (you earn money!)
235
- // await client.trackClick({ ... });
243
+ ```typescript
244
+ detectIntent("What is car insurance?") // → 'research'
245
+ detectIntent("Compare car insurance options") // → 'compare'
246
+ detectIntent("Get car insurance quote") // → 'quote'
247
+ detectIntent("I want to buy car insurance") // → 'apply'
248
+ ```
236
249
 
237
- return ad;
238
- }
250
+ #### `buildTaxonomy()` - Type-safe taxonomy builder
251
+ Constructs valid taxonomies like "insurance.auto.full_coverage.quote" with validation. Pass vertical, category, subcategory, and intent - it handles the formatting and catches errors.
239
252
 
240
- return null; // No ads available
241
- }
253
+ ```typescript
254
+ const taxonomy = buildTaxonomy('insurance', 'auto', 'full_coverage', 'quote');
255
+ // → "insurance.auto.full_coverage.quote"
256
+ ```
257
+
258
+ #### `suggestTaxonomies()` - Smart taxonomy recommendations
259
+ Pass a user query and get back 3-5 relevant taxonomy suggestions ranked by relevance. Great for when you're not sure which category to use.
242
260
 
243
- // Example usage
244
- await showRelevantAd("I need car insurance for my Honda");
245
- await showRelevantAd("I need a divorce lawyer in California");
261
+ ```typescript
262
+ const suggestions = suggestTaxonomies("I need a lawyer for divorce");
263
+ // ['legal.family.divorce.consultation', 'legal.family.custody.consultation']
246
264
  ```
247
265
 
266
+ #### Taxonomy Utilities
267
+ - `isValidTaxonomy(taxonomy)` - Validate taxonomy format
268
+ - `parseTaxonomy(taxonomy)` - Parse taxonomy into components
269
+ - `getBaseTaxonomy(taxonomy)` - Get taxonomy without intent
270
+ - `matchesTaxonomy(tax1, tax2)` - Check if taxonomies match
271
+ - `getVertical(taxonomy)` - Extract industry vertical
272
+
248
273
  ---
249
274
 
250
- ## API Reference
275
+ ### 🎨 Response Formatting
251
276
 
252
- ### Client Methods
277
+ #### `formatNatural()` - Convert ads into natural conversation
278
+ Transforms sponsored suggestions into conversational responses that feel native to your agent. Handles disclosure labels, CTA integration, and tone matching automatically.
253
279
 
254
- **`client.decide(request)`** - Get ads (convenience method)
255
280
  ```typescript
256
- const decision = await client.decide({
257
- request_id: crypto.randomUUID(),
258
- agent_id: 'your_agent_id',
259
- placement: { type: 'sponsored_suggestion' },
260
- opportunity: {
261
- intent: { taxonomy: 'insurance.auto.full_coverage.quote' },
262
- context: { country: 'US', language: 'en', platform: 'web' }
263
- }
281
+ const formatted = formatNatural(ad, {
282
+ tone: 'friendly',
283
+ includeDisclosure: true
264
284
  });
285
+ // → "I found a great option for you! [Sponsored: Lemonade]..."
265
286
  ```
266
287
 
267
- **`client.decideRaw(request)`** - Get full response with metadata
288
+ #### `formatInlineMention()` - Subtle in-message placement
289
+ Weaves ads into your agent's response as natural mentions. Like "Btw, Lemonade offers great rates for new drivers [Sponsored]". Less intrusive than separate ad blocks.
290
+
268
291
  ```typescript
269
- const response = await client.decideRaw(request);
270
- // Returns: { status, request_id, decision_id, units[], ttl_ms }
292
+ const mention = formatInlineMention(ad);
293
+ // "Btw, Lemonade offers 20% off for new drivers [Sponsored]"
271
294
  ```
272
295
 
273
- **`client.trackImpression(params)`** - Track when ad is shown
296
+ #### `validateAdFits()` - Check if ad matches conversation context
297
+ Before showing an ad, validate it fits the current conversation. Checks relevance, tone, and user intent to avoid jarring placements.
298
+
299
+ ```typescript
300
+ const fits = validateAdFits(ad, conversationContext);
301
+ if (fits) {
302
+ // Show the ad
303
+ }
304
+ ```
305
+
306
+ ---
307
+
308
+ ### 📊 Event Tracking
309
+
310
+ #### `trackImpression()` - Log when users see an ad
311
+ Record that an ad was shown to a user. Required for billing and analytics. Include the unit_id and tracking token from the ad response.
312
+
274
313
  ```typescript
275
314
  await client.trackImpression({
276
315
  agent_id: 'your_agent_id',
277
- request_id: 'req_123',
278
- decision_id: 'dec_456',
279
- unit_id: 'unit_789',
280
- tracking_token: 'trk_abc'
316
+ request_id: decision.request_id,
317
+ decision_id: decision.decision_id,
318
+ unit_id: ad.unit_id,
319
+ tracking_token: ad.tracking.token
281
320
  });
282
321
  ```
283
322
 
284
- **`client.trackClick(params)`** - Track when ad is clicked (you earn $)
323
+ #### `trackClick()` - Log when users click an ad
324
+ Record when users interact with ads. This is how you get paid. Automatically deduplicates to prevent double-charging.
325
+
326
+ **Required:** `click_context` - The actual message shown to the user that they clicked.
327
+
285
328
  ```typescript
286
329
  await client.trackClick({
287
330
  agent_id: 'your_agent_id',
288
- request_id: 'req_123',
289
- decision_id: 'dec_456',
290
- unit_id: 'unit_789',
291
- tracking_token: 'trk_abc',
292
- href: 'https://advertiser.com'
331
+ request_id: decision.request_id,
332
+ decision_id: decision.decision_id,
333
+ unit_id: ad.unit_id,
334
+ tracking_token: ad.tracking.token,
335
+ href: ad.suggestion.action_url,
336
+ click_context: 'The message shown to user when they clicked'
293
337
  });
294
338
  ```
295
339
 
296
- ### Helper Functions
340
+ ---
297
341
 
298
- - `buildTaxonomy(vertical, category, subcategory, intent?)` - Build taxonomy string
299
- - `detectIntent(query)` - Auto-detect user intent from query
300
- - `suggestTaxonomies(query)` - Get relevant taxonomy suggestions
301
- - `isValidTaxonomy(taxonomy)` - Validate taxonomy format
302
- - `parseTaxonomy(taxonomy)` - Parse taxonomy into components
303
- - `getBaseTaxonomy(taxonomy)` - Get taxonomy without intent
304
- - `matchesTaxonomy(tax1, tax2)` - Check if taxonomies match
305
- - `getVertical(taxonomy)` - Extract industry vertical
342
+ ### 🛠️ Helper Utilities
306
343
 
307
- ### Security Helpers
344
+ #### `createOpportunity()` - Build opportunity objects easily
345
+ Helper to construct the opportunity payload for decide() calls. Handles defaults and validation.
308
346
 
309
- - `escapeHTML(text)` - Escape HTML to prevent XSS
310
- - `sanitizeURL(url)` - Validate and sanitize URLs
347
+ ```typescript
348
+ const opportunity = createOpportunity({
349
+ taxonomy: 'insurance.auto.quote',
350
+ country: 'US'
351
+ });
352
+ ```
311
353
 
312
- **Always sanitize ad content before rendering!**
354
+ #### Security Helpers
355
+ - `escapeHTML(text)` - Sanitize ad content before rendering to prevent XSS attacks
356
+ - `sanitizeURL(url)` - Validate and sanitize URLs before opening
357
+
358
+ **Always sanitize ad content before displaying in web contexts!**
359
+
360
+ #### ID Generation
361
+ - `generateUUID()` - Create unique request IDs (crypto-secure randomness)
362
+ - `generateTimestamp()` - Generate timestamps that match our API requirements
313
363
 
314
364
  ---
315
365
 
316
- ## Testing
366
+ ### 🧪 Testing
317
367
 
318
- ### Mock Client (No API calls)
368
+ #### `MockAttentionMarketClient` - Test without real API calls
369
+ Drop-in replacement that returns fake ads for testing. Simulates latency, errors, and no-fill scenarios. Perfect for unit tests and local development.
319
370
 
320
371
  ```typescript
321
372
  import { MockAttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
@@ -330,42 +381,96 @@ const client = new MockAttentionMarketClient({
330
381
  const decision = await client.decide(request);
331
382
  ```
332
383
 
333
- ### Test Taxonomies
384
+ ---
385
+
386
+ ### ⚠️ Error Handling
387
+
388
+ #### `APIRequestError` - API returned an error response
389
+ Thrown when the backend rejects your request (invalid key, bad params, etc). Includes detailed error message and request_id for debugging.
390
+
391
+ #### `NetworkError` - Connection failed
392
+ Network issues, DNS failures, or backend unavailable. Includes automatic retry logic for transient failures.
393
+
394
+ #### `TimeoutError` - Request exceeded timeout
395
+ Request took too long (default 5s). Configure with `timeoutMs` in constructor.
334
396
 
335
- Use your test key with real API:
336
397
  ```typescript
337
- const client = new AttentionMarketClient({
338
- apiKey: process.env.ATTENTIONMARKET_TEST_KEY // am_test_...
339
- });
398
+ try {
399
+ const decision = await client.decide(request);
400
+ } catch (error) {
401
+ if (error instanceof TimeoutError) {
402
+ console.log('Request timed out, try again');
403
+ } else if (error instanceof NetworkError) {
404
+ console.log('Network issue, retrying...');
405
+ } else if (error instanceof APIRequestError) {
406
+ console.log('API error:', error.message);
407
+ }
408
+ }
340
409
  ```
341
410
 
411
+ </details>
412
+
342
413
  ---
343
414
 
344
- ## Security
415
+ ## Using Test vs Live Keys
345
416
 
346
- ### ⚠️ CRITICAL: Server-Side Only
417
+ ### Test Environment
418
+ Use your test key for development:
419
+ ```typescript
420
+ const client = new AttentionMarketClient({
421
+ apiKey: process.env.ATTENTIONMARKET_TEST_KEY // am_test_...
422
+ });
423
+ ```
347
424
 
348
- **Never use this SDK in browsers or mobile apps.** Your API key has full access to your account.
425
+ ### Production Environment
426
+ Use your live key for production:
427
+ ```typescript
428
+ const client = new AttentionMarketClient({
429
+ apiKey: process.env.ATTENTIONMARKET_API_KEY // am_live_...
430
+ });
431
+ ```
349
432
 
350
- ✅ **Safe:** Node.js, serverless functions, server-side rendering
351
- ❌ **Unsafe:** Browser JavaScript, React/Vue components, mobile apps
433
+ ---
352
434
 
353
- ### Sanitize Ad Content
435
+ ## Sanitizing Ad Content
354
436
 
355
- Always escape ad content before rendering:
437
+ Ad creative comes from third-party advertisers. Always sanitize before rendering in HTML contexts:
356
438
 
357
439
  ```typescript
358
440
  import { escapeHTML, sanitizeURL } from '@the_ro_show/agent-ads-sdk';
359
441
 
360
- const safeTitle = escapeHTML(ad.suggestion.title);
361
- const safeURL = sanitizeURL(ad.suggestion.action_url);
442
+ const safeTitle = escapeHTML(ad.creative.title);
443
+ const safeURL = sanitizeURL(ad.click_url);
362
444
 
363
445
  if (safeURL) {
364
446
  element.innerHTML = `<a href="${safeURL}">${safeTitle}</a>`;
365
447
  }
366
448
  ```
367
449
 
368
- **See [SECURITY.md](./SECURITY.md) for complete guidelines.**
450
+ <details>
451
+ <summary><strong>Security considerations</strong></summary>
452
+
453
+ <br>
454
+
455
+ ### Server-Side Only
456
+
457
+ This SDK must run server-side. Do not use in browsers or mobile apps where the API key would be exposed.
458
+
459
+ **Supported:**
460
+ - Node.js servers
461
+ - Serverless functions (AWS Lambda, Vercel, Cloudflare Workers)
462
+ - Server-side rendering (Next.js, Remix)
463
+
464
+ **Not supported:**
465
+ - Browser JavaScript
466
+ - Client-side React/Vue/Angular
467
+ - Mobile apps
468
+
469
+ ### Additional Guidelines
470
+
471
+ See [SECURITY.md](./SECURITY.md) for complete security best practices.
472
+
473
+ </details>
369
474
 
370
475
  ---
371
476
 
@@ -432,6 +537,61 @@ npx tsx examples/claude-tool-use-minimal.ts
432
537
 
433
538
  ---
434
539
 
540
+ ## Available Ad Categories
541
+
542
+ The network currently has active campaigns in these verticals:
543
+
544
+ | Category | CPC Range | Common Intents |
545
+ |----------|-----------|----------------|
546
+ | Legal | $50-150 | Divorce, estate planning, personal injury, immigration |
547
+ | Insurance | $20-54 | Auto, home, life, health |
548
+ | Financial | $15-50 | Loans, credit cards, mortgages, investing |
549
+ | B2B SaaS | $10-100 | CRM, project management, ecommerce tools |
550
+ | Home Services | $5-30 | Moving, cleaning, repairs |
551
+ | Travel | $3-20 | Flights, hotels, packages |
552
+ | Ecommerce | $2-15 | Retail, subscriptions |
553
+ | Education | $10-50 | Courses, certifications |
554
+
555
+ The semantic matching API automatically maps user queries to available inventory. If your use case isn't listed, contact support@attentionmarket.com to discuss adding new categories.
556
+
557
+ <details>
558
+ <summary><strong>View detailed taxonomy reference (advanced users only)</strong></summary>
559
+
560
+ <br>
561
+
562
+ **Full taxonomy list:** [TAXONOMY_SYSTEM.md](./TAXONOMY_SYSTEM.md)
563
+
564
+ Example taxonomies for advanced `decide()` API:
565
+ ```typescript
566
+ // Insurance
567
+ 'insurance.auto.full_coverage.quote'
568
+ 'insurance.auto.liability.compare'
569
+ 'insurance.home.standard.quote'
570
+ 'insurance.life.term.compare'
571
+
572
+ // Legal
573
+ 'legal.personal_injury.accident.consultation'
574
+ 'legal.family.divorce.consultation'
575
+ 'legal.estate_planning.will.consultation'
576
+
577
+ // Financial
578
+ 'financial.loans.personal.quote'
579
+ 'financial.credit_cards.rewards.compare'
580
+ 'financial.investing.brokerage.trial'
581
+
582
+ // B2B SaaS
583
+ 'business.saas.crm.trial'
584
+ 'business.saas.project_management.trial'
585
+
586
+ // Home Services
587
+ 'home_services.moving.local.quote'
588
+ 'home_services.plumbing.emergency.quote'
589
+ ```
590
+
591
+ </details>
592
+
593
+ ---
594
+
435
595
  ## Support
436
596
 
437
597
  - **Issues:** [GitHub Issues](https://github.com/rtrivedi/agent-ads-sdk/issues)
@@ -448,27 +608,4 @@ MIT
448
608
 
449
609
  ## Changelog
450
610
 
451
- ### v0.4.0 (2026-02-03)
452
-
453
- **New Features:**
454
- - ✨ Hierarchical taxonomy matching (3x more inventory)
455
- - ✨ `buildTaxonomy()` helper function
456
- - ✨ `detectIntent()` auto-intent detection
457
- - ✨ `suggestTaxonomies()` get relevant taxonomies
458
- - ✨ `isValidTaxonomy()` and `parseTaxonomy()` validators
459
- - ✨ 50 Phase 1 high-value taxonomies (insurance, legal, finance, etc.)
460
-
461
- **Improvements:**
462
- - 🎯 Relevance scoring (1.0 → 0.9 → 0.7 → 0.5)
463
- - 🔄 Backward compatibility for old taxonomies (90-day migration window)
464
- - 📚 Complete taxonomy documentation
465
-
466
- **Breaking Changes:**
467
- - None! Fully backward compatible.
468
-
469
- ### v0.2.1
470
-
471
- - Initial public release
472
- - Multi-ad response support
473
- - Mock client for testing
474
- - Security helpers (escapeHTML, sanitizeURL)
611
+ See [CHANGELOG.md](./CHANGELOG.md) for detailed version history.