@the_ro_show/agent-ads-sdk 0.4.0 → 0.4.2

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
@@ -1,553 +1,474 @@
1
1
  # AttentionMarket Agent Ads SDK
2
2
 
3
- TypeScript SDK for integrating agent-native sponsored units (Sponsored Suggestions and Sponsored Tools) into AI agents.
3
+ [![npm version](https://badge.fury.io/js/@the_ro_show%2Fagent-ads-sdk.svg)](https://www.npmjs.com/package/@the_ro_show/agent-ads-sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
4
6
 
5
- ## 🚀 New to this? Start Here
7
+ **The first ad network built for AI agents.** Monetize your AI agent with contextual, high-intent sponsored suggestions. Open source, transparent, developer-first.
6
8
 
7
- **→ [Simple Integration Guide](./SIMPLE_INTEGRATION_GUIDE.md)** - Step-by-step guide for Clawdbot/Moltbot developers
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
8
13
 
9
- This README contains the full API reference. If you're just getting started, the Simple Integration Guide is much easier to follow!
10
-
11
- ---
14
+ ## Quick Start
12
15
 
13
- ## Installation
16
+ ### 1. Get Your API Key
14
17
 
15
- ```bash
16
- npm install @the_ro_show/agent-ads-sdk
17
- ```
18
+ **Sign up at [attentionmarket.com/signup](https://attentionmarket.com/signup)** (30 seconds, free forever)
18
19
 
19
- ## Configuration
20
+ You'll receive:
21
+ - Test key: `am_test_...` (for development)
22
+ - Live key: `am_live_...` (for production)
20
23
 
21
- Store your credentials in environment variables:
24
+ ### 2. Install
22
25
 
23
26
  ```bash
24
- export ATTENTIONMARKET_API_KEY=am_live_...
25
- export ATTENTIONMARKET_AGENT_ID=agt_01HV...
27
+ npm install @the_ro_show/agent-ads-sdk
26
28
  ```
27
29
 
28
- **⚠️ Never commit API keys to version control.** See [SECURITY.md](./SECURITY.md) for best practices.
29
-
30
- ## Quick Start
30
+ ### 3. Integrate (5 lines of code)
31
31
 
32
32
  ```typescript
33
- import { AttentionMarketClient, createOpportunity, generateUUID } from '@the_ro_show/agent-ads-sdk';
34
-
35
- const client = new AttentionMarketClient({ apiKey: process.env.ATTENTIONMARKET_API_KEY });
33
+ import { AttentionMarketClient, detectIntent, buildTaxonomy } from '@the_ro_show/agent-ads-sdk';
36
34
 
37
- const opportunity = createOpportunity({
38
- taxonomy: 'local_services.movers.quote',
39
- country: 'US',
40
- language: 'en',
41
- platform: 'web',
42
- query: 'Find movers in Brooklyn',
35
+ const client = new AttentionMarketClient({
36
+ apiKey: process.env.ATTENTIONMARKET_API_KEY // Your test or live key
43
37
  });
44
38
 
45
- const unit = await client.decide({
46
- request_id: generateUUID(),
47
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
48
- placement: { type: 'sponsored_suggestion', surface: 'chat_response' },
49
- opportunity,
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
+ }
50
52
  });
51
53
 
52
- if (unit && unit.unit_type === 'sponsored_suggestion') {
53
- console.log(`[${unit.disclosure.label}] ${unit.disclosure.sponsor_name}`);
54
- console.log(unit.suggestion.title);
55
-
56
- await client.trackImpression({
57
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
58
- request_id: 'req_id',
59
- decision_id: 'decision_id',
60
- unit_id: unit.unit_id,
61
- tracking_token: unit.tracking.token,
62
- });
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
63
58
  }
64
59
  ```
65
60
 
66
- ## Security Best Practices
67
-
68
- 🔴 **CRITICAL SECURITY REQUIREMENTS**
61
+ **That's it!** Start earning from relevant ads.
69
62
 
70
- ### 1. Server-Side Only
71
-
72
- **This SDK MUST only be used server-side.** Your API key provides full access to your account and billing.
63
+ ---
73
64
 
74
- **Safe:** Node.js, serverless functions, server-side rendering
75
- ❌ **Unsafe:** Browser JavaScript, mobile apps without backend proxy
65
+ ## 🆕 What's New in v0.4.0
76
66
 
77
- ### 2. Sanitize Ad Content Before Display
67
+ ### Hierarchical Taxonomy Matching
78
68
 
79
- Ad content can contain malicious HTML/JavaScript. **Always sanitize** before rendering in HTML:
69
+ Target broadly, match specifically:
80
70
 
81
71
  ```typescript
82
- import { escapeHTML, sanitizeURL } from '@the_ro_show/agent-ads-sdk';
72
+ // Advertiser targets: "insurance.auto"
73
+ // Your agent requests: "insurance.auto.full_coverage.quote"
74
+ // ✅ Matches! (0.7 relevance score)
83
75
 
84
- // SAFE: Sanitize content
85
- const safeTitle = escapeHTML(unit.suggestion.title);
86
- const safeBody = escapeHTML(unit.suggestion.body);
87
- const safeURL = sanitizeURL(unit.suggestion.action_url);
76
+ // Your agent requests: "insurance.auto.liability.compare"
77
+ // Also matches! (0.7 relevance score)
88
78
 
89
- if (safeURL) {
90
- element.innerHTML = `<a href="${safeURL}">${safeTitle}</a>`;
91
- }
79
+ // Your agent requests: "insurance.home.flood.quote"
80
+ // No match (different category)
92
81
  ```
93
82
 
94
- ```typescript
95
- // ❌ DANGEROUS: Direct HTML injection (XSS vulnerability!)
96
- element.innerHTML = unit.suggestion.title;
97
- ```
83
+ **Result:** 3x more ad inventory, higher fill rates.
98
84
 
99
- ### 3. Validate URLs
100
-
101
- Always validate `action_url` before using:
85
+ ### New Helper Functions
102
86
 
87
+ **Auto-detect user intent:**
103
88
  ```typescript
104
- const safeURL = sanitizeURL(unit.suggestion.action_url);
89
+ import { detectIntent } from '@the_ro_show/agent-ads-sdk';
105
90
 
106
- if (!safeURL) {
107
- console.error('Dangerous URL blocked');
108
- return; // Don't render the ad
109
- }
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'
110
95
  ```
111
96
 
112
- Blocks dangerous protocols: `javascript:`, `data:`, `file:`
113
-
114
- ### 4. See Complete Guidelines
97
+ **Build taxonomies easily:**
98
+ ```typescript
99
+ import { buildTaxonomy } from '@the_ro_show/agent-ads-sdk';
115
100
 
116
- 📖 **[Read SECURITY.md](./SECURITY.md)** for comprehensive security guidelines including:
117
- - XSS prevention examples
118
- - Phishing protection
119
- - Rate limiting
120
- - Input validation
121
- - Security checklist
101
+ const taxonomy = buildTaxonomy('insurance', 'auto', 'full_coverage', 'quote');
102
+ // "insurance.auto.full_coverage.quote"
103
+ ```
122
104
 
123
- ## Testing Without Advertiser Data
105
+ **Get taxonomy suggestions:**
106
+ ```typescript
107
+ import { suggestTaxonomies } from '@the_ro_show/agent-ads-sdk';
124
108
 
125
- Use `MockAttentionMarketClient` to test your integration without needing real ad campaigns.
109
+ const suggestions = suggestTaxonomies("I need a lawyer for divorce");
110
+ // → ['legal.family.divorce.consultation', 'legal.family.custody.consultation']
111
+ ```
126
112
 
113
+ **Validate taxonomies:**
127
114
  ```typescript
128
- import { MockAttentionMarketClient, createOpportunity, generateUUID } from '@the_ro_show/agent-ads-sdk';
115
+ import { isValidTaxonomy, parseTaxonomy } from '@the_ro_show/agent-ads-sdk';
129
116
 
130
- // Use mock client during development
131
- const client = new MockAttentionMarketClient({
132
- latencyMs: 100, // Simulate API latency
133
- fillRate: 1.0, // 100% fill rate for testing
134
- verbose: true, // Log mock activity
135
- });
136
-
137
- const opportunity = createOpportunity({
138
- taxonomy: 'local_services.movers.quote',
139
- country: 'US',
140
- language: 'en',
141
- platform: 'web',
142
- query: 'Find movers in Brooklyn',
143
- });
117
+ isValidTaxonomy('insurance.auto.full_coverage.quote') // true
118
+ isValidTaxonomy('invalid.format') // false
144
119
 
145
- const unit = await client.decide({
146
- request_id: generateUUID(),
147
- agent_id: 'agt_test',
148
- placement: { type: 'sponsored_suggestion', surface: 'chat_response' },
149
- opportunity,
150
- });
151
-
152
- // Returns realistic mock ad data immediately
153
- if (unit && unit.unit_type === 'sponsored_suggestion') {
154
- console.log(unit.suggestion.title); // "Professional Moving Services - Same Day Available"
155
- }
120
+ const parsed = parseTaxonomy('insurance.auto.full_coverage.quote');
121
+ // → { vertical: 'insurance', category: 'auto', subcategory: 'full_coverage', intent: 'quote' }
156
122
  ```
157
123
 
158
- **Available mock taxonomies:**
159
- - `local_services.movers.quote`
160
- - `local_services.restaurants.search`
161
- - `local_services.plumbers.quote`
162
- - `local_services.electricians.quote`
163
- - `local_services.cleaners.quote`
164
- - `shopping.electronics.search`
124
+ ---
165
125
 
166
- **Add custom mock ads:**
126
+ ## Common Taxonomies
167
127
 
128
+ ### Insurance ($20-54 CPC)
168
129
  ```typescript
169
- client.addMockUnit('your.custom.taxonomy', {
170
- unit_id: 'unit_custom_001',
171
- unit_type: 'sponsored_suggestion',
172
- disclosure: { label: 'Sponsored', sponsor_name: 'Your Sponsor' },
173
- tracking: { token: 'trk_test', impression_url: '...', click_url: '...' },
174
- suggestion: {
175
- title: 'Your Ad Title',
176
- body: 'Your ad body text',
177
- cta: 'Call to Action',
178
- action_url: 'https://example.com',
179
- },
180
- });
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'
181
135
  ```
182
136
 
183
- **Run the full test suite:**
184
-
185
- ```bash
186
- npx tsx examples/test-with-mocks.ts
137
+ ### Legal ($50-150 CPC)
138
+ ```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'
187
144
  ```
188
145
 
189
- **Switch to production:**
190
-
146
+ ### Financial Services ($15-50 CPC)
191
147
  ```typescript
192
- const client = process.env.NODE_ENV === 'production'
193
- ? new AttentionMarketClient({ apiKey: process.env.ATTENTIONMARKET_API_KEY })
194
- : new MockAttentionMarketClient();
148
+ 'financial.loans.personal.quote'
149
+ 'financial.loans.mortgage.compare'
150
+ 'financial.credit_cards.rewards.compare'
151
+ 'financial.investing.brokerage.trial'
195
152
  ```
196
153
 
197
- ## Agent Integration Examples
198
-
199
- ### Minimal Examples (< 80 lines)
200
-
201
- Start here for a quick overview:
202
-
203
- - **[Claude](./examples/claude-tool-use-minimal.ts)** - Minimal tool use integration
204
- - **[OpenAI GPT](./examples/openai-function-calling-minimal.ts)** - Minimal function calling
205
- - **[Google Gemini](./examples/gemini-function-calling-minimal.ts)** - Minimal function declarations
206
-
207
- Each shows: `createOpportunity` → `decide` → render → track
208
-
209
- ### Full Examples (with detailed integration notes)
154
+ ### B2B SaaS ($10-100 CPC)
155
+ ```typescript
156
+ 'business.saas.crm.trial'
157
+ 'business.saas.project_management.trial'
158
+ 'business.ecommerce.platform.trial'
159
+ 'business.saas.marketing_automation.trial'
160
+ ```
210
161
 
211
- For production integrations:
162
+ ### Home Services ($5-30 CPC)
163
+ ```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'
168
+ ```
212
169
 
213
- - **[Claude (Anthropic)](./examples/claude-tool-use-full.ts)** - Complete tool use pattern with schemas and tracking
214
- - **[OpenAI GPT](./examples/openai-function-calling-full.ts)** - Complete function calling with integration checklist
215
- - **[Google Gemini](./examples/gemini-function-calling-full.ts)** - Complete function declarations with testing guide
216
- - **[Safe Web Rendering](./examples/safe-web-rendering.ts)** - XSS prevention and secure HTML rendering
170
+ **See all 50+ taxonomies:** [TAXONOMY_SYSTEM.md](./TAXONOMY_SYSTEM.md)
217
171
 
218
- Run any example with:
219
- ```bash
220
- npx tsx examples/claude-tool-use-minimal.ts
221
- npx tsx examples/safe-web-rendering.ts
222
- ```
172
+ ---
223
173
 
224
- ## Full Example with Raw Response
174
+ ## Complete Example
225
175
 
226
176
  ```typescript
227
177
  import {
228
178
  AttentionMarketClient,
229
- createOpportunity,
230
- generateUUID,
179
+ buildTaxonomy,
180
+ detectIntent
231
181
  } from '@the_ro_show/agent-ads-sdk';
232
182
 
233
183
  const client = new AttentionMarketClient({
234
- apiKey: process.env.ATTENTIONMARKET_API_KEY,
184
+ apiKey: process.env.ATTENTIONMARKET_API_KEY
235
185
  });
236
186
 
237
- // Build opportunity
238
- const opportunity = createOpportunity({
239
- taxonomy: 'local_services.movers.quote',
240
- country: 'US',
241
- language: 'en',
242
- platform: 'web',
243
- query: 'Find movers in Brooklyn',
244
- });
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
+ }
245
200
 
246
- // Get full response (includes status, ttl_ms, all units)
247
- const response = await client.decideRaw({
248
- request_id: generateUUID(),
249
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
250
- placement: {
251
- type: 'sponsored_suggestion',
252
- surface: 'chat_response',
253
- },
254
- opportunity,
255
- });
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
+ });
256
215
 
257
- if (response.status === 'filled') {
258
- // Access all units and metadata
259
- console.log(`TTL: ${response.ttl_ms}ms`);
260
- console.log(`Units: ${response.units.length}`);
216
+ // 4. Show ad if available
217
+ if (decision.status === 'filled') {
218
+ const ad = decision.units[0];
261
219
 
262
- const unit = response.units[0];
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`);
263
224
 
264
- // Render unit
265
- if (unit && unit.unit_type === 'sponsored_suggestion') {
266
- console.log(unit.suggestion.title);
267
- }
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
+ });
268
233
 
269
- // Track impression after rendering
270
- await client.trackImpression({
271
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
272
- request_id: response.request_id,
273
- decision_id: response.decision_id,
274
- unit_id: unit.unit_id,
275
- tracking_token: unit.tracking.token,
276
- metadata: { surface: 'chat_response' },
277
- });
234
+ // 6. Track click when user clicks (you earn money!)
235
+ // await client.trackClick({ ... });
278
236
 
279
- // Track click when user clicks
280
- await client.trackClick({
281
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
282
- request_id: response.request_id,
283
- decision_id: response.decision_id,
284
- unit_id: unit.unit_id,
285
- tracking_token: unit.tracking.token,
286
- href: unit.suggestion.action_url,
287
- });
237
+ return ad;
238
+ }
239
+
240
+ return null; // No ads available
288
241
  }
242
+
243
+ // Example usage
244
+ await showRelevantAd("I need car insurance for my Honda");
245
+ await showRelevantAd("I need a divorce lawyer in California");
289
246
  ```
290
247
 
291
- ## API Methods
248
+ ---
292
249
 
293
- ### `decide(request, options?): Promise<AdUnit | null>`
250
+ ## API Reference
294
251
 
295
- Convenience method that returns the first ad unit or `null` if no fill.
252
+ ### Client Methods
296
253
 
254
+ **`client.decide(request)`** - Get ads (convenience method)
297
255
  ```typescript
298
- const unit = await client.decide({
299
- request_id: generateUUID(),
300
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
301
- placement: {
302
- type: 'sponsored_suggestion',
303
- surface: 'chat_response',
304
- },
305
- opportunity,
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
+ }
306
264
  });
307
265
  ```
308
266
 
309
- ### `decideRaw(request, options?): Promise<DecideResponse>`
310
-
311
- Returns the full response including status, ttl_ms, and all units.
312
-
267
+ **`client.decideRaw(request)`** - Get full response with metadata
313
268
  ```typescript
314
- const response = await client.decideRaw({
315
- request_id: generateUUID(),
316
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
317
- placement: { type: 'sponsored_suggestion', surface: 'chat_response' },
318
- opportunity,
319
- }, {
320
- idempotencyKey: 'optional-idempotency-key',
321
- });
269
+ const response = await client.decideRaw(request);
270
+ // Returns: { status, request_id, decision_id, units[], ttl_ms }
322
271
  ```
323
272
 
324
- ### `trackImpression(params): Promise<EventIngestResponse>`
325
-
326
- Convenience method to track when a unit is rendered.
327
-
273
+ **`client.trackImpression(params)`** - Track when ad is shown
328
274
  ```typescript
329
275
  await client.trackImpression({
330
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
276
+ agent_id: 'your_agent_id',
331
277
  request_id: 'req_123',
332
278
  decision_id: 'dec_456',
333
279
  unit_id: 'unit_789',
334
- tracking_token: 'trk_abc',
335
- metadata: { surface: 'chat_response' },
280
+ tracking_token: 'trk_abc'
336
281
  });
337
282
  ```
338
283
 
339
- ### `trackClick(params): Promise<EventIngestResponse>`
340
-
341
- Convenience method to track when a user clicks a unit.
342
-
284
+ **`client.trackClick(params)`** - Track when ad is clicked (you earn $)
343
285
  ```typescript
344
286
  await client.trackClick({
345
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
287
+ agent_id: 'your_agent_id',
346
288
  request_id: 'req_123',
347
289
  decision_id: 'dec_456',
348
290
  unit_id: 'unit_789',
349
291
  tracking_token: 'trk_abc',
350
- href: 'https://example.com/action',
292
+ href: 'https://advertiser.com'
351
293
  });
352
294
  ```
353
295
 
354
- ### `track(event): Promise<EventIngestResponse>`
296
+ ### Helper Functions
355
297
 
356
- Low-level method to track any event type.
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
357
306
 
358
- ```typescript
359
- await client.track({
360
- event_id: generateUUID(),
361
- occurred_at: new Date().toISOString(),
362
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
363
- request_id: 'req_123',
364
- decision_id: 'dec_456',
365
- unit_id: 'unit_789',
366
- event_type: 'impression',
367
- tracking_token: 'trk_abc',
368
- });
369
- ```
307
+ ### Security Helpers
370
308
 
371
- ### `getPolicy(): Promise<PolicyResponse>`
309
+ - `escapeHTML(text)` - Escape HTML to prevent XSS
310
+ - `sanitizeURL(url)` - Validate and sanitize URLs
372
311
 
373
- Fetch policy constraints and formatting requirements.
312
+ **Always sanitize ad content before rendering!**
374
313
 
375
- ```typescript
376
- const policy = await client.getPolicy();
377
- console.log(policy.defaults.max_units_per_response);
378
- console.log(policy.disclosure.label);
379
- ```
314
+ ---
380
315
 
381
- ### `signupAgent(request, options?): Promise<AgentSignupResponse>` (static)
316
+ ## Testing
382
317
 
383
- Register a new agent (unauthenticated endpoint).
318
+ ### Mock Client (No API calls)
384
319
 
385
320
  ```typescript
386
- const signup = await AttentionMarketClient.signupAgent({
387
- owner_email: 'owner@company.com',
388
- agent_name: 'My Agent',
389
- sdk: 'typescript',
390
- environment: 'test',
321
+ import { MockAttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
322
+
323
+ const client = new MockAttentionMarketClient({
324
+ fillRate: 1.0, // Always return ads
325
+ latencyMs: 100, // Simulate API latency
326
+ verbose: true // Log activity
391
327
  });
392
328
 
393
- console.log(signup.agent_id);
394
- console.log(signup.api_key);
329
+ // Works exactly like real client, but returns mock data
330
+ const decision = await client.decide(request);
395
331
  ```
396
332
 
397
- ## Helper Functions
398
-
399
- ### `createOpportunity(params): Opportunity`
400
-
401
- Build a valid Opportunity object with safe defaults.
333
+ ### Test Taxonomies
402
334
 
335
+ Use your test key with real API:
403
336
  ```typescript
404
- const opportunity = createOpportunity({
405
- // Required
406
- taxonomy: 'local_services.movers.quote',
407
- country: 'US',
408
- language: 'en',
409
- platform: 'web',
410
-
411
- // Optional
412
- query: 'Find movers in Brooklyn',
413
- region: 'NY',
414
- city: 'New York',
415
-
416
- // Optional overrides (with defaults shown)
417
- constraints: {
418
- max_units: 1,
419
- allowed_unit_types: ['sponsored_suggestion'],
420
- blocked_categories: ['adult'],
421
- },
422
- privacy: {
423
- data_policy: 'coarse_only',
424
- },
337
+ const client = new AttentionMarketClient({
338
+ apiKey: process.env.ATTENTIONMARKET_TEST_KEY // am_test_...
425
339
  });
426
340
  ```
427
341
 
428
- ### `createImpressionEvent(params): EventIngestRequest`
342
+ ---
429
343
 
430
- Build an impression event payload.
344
+ ## Security
431
345
 
432
- ```typescript
433
- import { createImpressionEvent } from '@the_ro_show/agent-ads-sdk';
346
+ ### ⚠️ CRITICAL: Server-Side Only
434
347
 
435
- const event = createImpressionEvent({
436
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
437
- request_id: 'req_123',
438
- decision_id: 'dec_456',
439
- unit_id: 'unit_789',
440
- tracking_token: 'trk_abc',
441
- occurred_at: new Date().toISOString(), // optional, auto-generated
442
- metadata: { surface: 'chat_response' }, // optional
443
- });
348
+ **Never use this SDK in browsers or mobile apps.** Your API key has full access to your account.
444
349
 
445
- await client.track(event);
446
- ```
350
+ **Safe:** Node.js, serverless functions, server-side rendering
351
+ ❌ **Unsafe:** Browser JavaScript, React/Vue components, mobile apps
447
352
 
448
- ### `createClickEvent(params): EventIngestRequest`
353
+ ### Sanitize Ad Content
449
354
 
450
- Build a click event payload.
355
+ Always escape ad content before rendering:
451
356
 
452
357
  ```typescript
453
- import { createClickEvent } from '@the_ro_show/agent-ads-sdk';
358
+ import { escapeHTML, sanitizeURL } from '@the_ro_show/agent-ads-sdk';
454
359
 
455
- const event = createClickEvent({
456
- agent_id: process.env.ATTENTIONMARKET_AGENT_ID,
457
- request_id: 'req_123',
458
- decision_id: 'dec_456',
459
- unit_id: 'unit_789',
460
- tracking_token: 'trk_abc',
461
- href: 'https://example.com',
462
- occurred_at: new Date().toISOString(), // optional, auto-generated
463
- });
360
+ const safeTitle = escapeHTML(ad.suggestion.title);
361
+ const safeURL = sanitizeURL(ad.suggestion.action_url);
464
362
 
465
- await client.track(event);
363
+ if (safeURL) {
364
+ element.innerHTML = `<a href="${safeURL}">${safeTitle}</a>`;
365
+ }
466
366
  ```
467
367
 
468
- ### `generateUUID(): string`
368
+ **See [SECURITY.md](./SECURITY.md) for complete guidelines.**
469
369
 
470
- Generate a UUID v4 for request_id, event_id, etc.
370
+ ---
471
371
 
472
- ```typescript
473
- import { generateUUID } from '@the_ro_show/agent-ads-sdk';
372
+ ## Examples
474
373
 
475
- const requestId = generateUUID();
476
- ```
374
+ **Minimal integrations** (< 80 lines):
375
+ - [Claude Tool Use](./examples/claude-tool-use-minimal.ts)
376
+ - [OpenAI Function Calling](./examples/openai-function-calling-minimal.ts)
377
+ - [Google Gemini](./examples/gemini-function-calling-minimal.ts)
477
378
 
478
- ### `escapeHTML(text): string`
379
+ **Full integrations** (production-ready):
380
+ - [Claude Complete](./examples/claude-tool-use-full.ts)
381
+ - [OpenAI Complete](./examples/openai-function-calling-full.ts)
382
+ - [Safe Web Rendering](./examples/safe-web-rendering.ts)
479
383
 
480
- Escape HTML special characters to prevent XSS attacks.
384
+ Run any example:
385
+ ```bash
386
+ npx tsx examples/claude-tool-use-minimal.ts
387
+ ```
481
388
 
482
- ```typescript
483
- import { escapeHTML } from '@the_ro_show/agent-ads-sdk';
389
+ ---
484
390
 
485
- const safeTitle = escapeHTML(unit.suggestion.title);
486
- element.innerHTML = safeTitle; // Safe from XSS
487
- ```
391
+ ## Documentation
488
392
 
489
- Escapes: `&`, `<`, `>`, `"`, `'`, `/`
393
+ - **[Simple Integration Guide](./SIMPLE_INTEGRATION_GUIDE.md)** - Step-by-step for beginners
394
+ - **[Taxonomy System](./TAXONOMY_SYSTEM.md)** - Complete taxonomy reference
395
+ - **[Migration Guide](./TAXONOMY_MIGRATION_GUIDE.md)** - Upgrading from older versions
396
+ - **[Security Guide](./SECURITY.md)** - Security best practices
397
+ - **[Advertiser Guide](./ADVERTISER_ONBOARDING_GUIDE.md)** - For advertisers
490
398
 
491
- ### `sanitizeURL(url, options?): string | null`
399
+ ---
492
400
 
493
- Validate and sanitize URLs to prevent XSS and phishing attacks.
401
+ ## Features
494
402
 
495
- ```typescript
496
- import { sanitizeURL } from '@the_ro_show/agent-ads-sdk';
403
+ - ✅ **Hierarchical matching** - Advertisers target broadly, agents match specifically
404
+ - **Auto-intent detection** - Automatically detect research vs quote vs apply
405
+ - ✅ **50+ high-value taxonomies** - Insurance, legal, finance, B2B SaaS, and more
406
+ - ✅ **TypeScript support** - Full type definitions included
407
+ - ✅ **Automatic retries** - Exponential backoff for failed requests
408
+ - ✅ **Mock client** - Test without API calls
409
+ - ✅ **Security helpers** - XSS protection, URL sanitization
410
+ - ✅ **Zero dependencies** - No external runtime dependencies
497
411
 
498
- const safeURL = sanitizeURL(unit.suggestion.action_url);
412
+ ---
499
413
 
500
- if (safeURL) {
501
- window.open(safeURL, '_blank');
502
- } else {
503
- console.error('Dangerous URL blocked');
504
- }
505
- ```
414
+ ## Pricing
506
415
 
507
- **Blocked protocols:** `javascript:`, `data:`, `file:`, `vbscript:`
416
+ **Free to use.** You earn money when users click ads:
508
417
 
509
- **Options:**
510
- - `allowHttp: boolean` - Allow HTTP URLs (default: false, HTTPS only)
511
- - `allowTel: boolean` - Allow tel: links (default: true)
512
- - `allowMailto: boolean` - Allow mailto: links (default: true)
418
+ - **Insurance:** $20-54 per click
419
+ - **Legal:** $50-150 per click
420
+ - **Financial:** $15-50 per click
421
+ - **B2B SaaS:** $10-100 per click
422
+ - **Home Services:** $5-30 per click
513
423
 
514
- ## Features
424
+ **You keep 70% of revenue.** Paid monthly via Stripe.
515
425
 
516
- - ✅ TypeScript support with full type definitions
517
- - ✅ Automatic retries with exponential backoff
518
- - ✅ Configurable timeouts (default 4000ms)
519
- - ✅ Idempotency support
520
- - ✅ Discriminated union types for type-safe ad units
521
- - ✅ Helper functions for common operations
522
- - ✅ No external runtime dependencies (Node.js 18+)
426
+ ---
523
427
 
524
428
  ## Requirements
525
429
 
526
430
  - Node.js 18 or higher
527
- - TypeScript 5.3 or higher (for development)
431
+ - TypeScript 5.3+ (for development)
528
432
 
529
- ## Error Handling
433
+ ---
530
434
 
531
- The SDK throws typed errors that include full API context:
435
+ ## Support
532
436
 
533
- ```typescript
534
- import { APIRequestError, NetworkError, TimeoutError } from '@the_ro_show/agent-ads-sdk';
535
-
536
- try {
537
- const unit = await client.decide(request);
538
- } catch (error) {
539
- if (error instanceof APIRequestError) {
540
- console.error(`API Error [${error.statusCode}]: ${error.errorCode}`);
541
- console.error(`Message: ${error.message}`);
542
- console.error(`Request ID: ${error.requestId}`);
543
- } else if (error instanceof TimeoutError) {
544
- console.error('Request timed out');
545
- } else if (error instanceof NetworkError) {
546
- console.error('Network error:', error.message);
547
- }
548
- }
549
- ```
437
+ - **Issues:** [GitHub Issues](https://github.com/rtrivedi/agent-ads-sdk/issues)
438
+ - **Docs:** [SIMPLE_INTEGRATION_GUIDE.md](./SIMPLE_INTEGRATION_GUIDE.md)
439
+ - **Email:** support@attentionmarket.com
440
+
441
+ ---
550
442
 
551
443
  ## License
552
444
 
553
445
  MIT
446
+
447
+ ---
448
+
449
+ ## Changelog
450
+
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)