@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 +381 -244
- package/dist/index.d.mts +266 -1
- package/dist/index.d.ts +266 -1
- package/dist/index.js +332 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +332 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,22 +4,21 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
-
|
|
10
|
-
-
|
|
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
|
-
|
|
12
|
+
---
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
## Quick Start
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
### 1. Get API Key
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
- Test key: `am_test_...`
|
|
22
|
-
- Live key: `am_live_...`
|
|
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.
|
|
29
|
+
### 3. Basic Usage
|
|
31
30
|
|
|
32
31
|
```typescript
|
|
33
|
-
import { AttentionMarketClient
|
|
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
|
|
35
|
+
apiKey: process.env.ATTENTIONMARKET_API_KEY,
|
|
36
|
+
agentId: 'your_agent_id'
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
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 (
|
|
55
|
-
|
|
56
|
-
console.log(
|
|
57
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
60
|
+
The API handles intent detection and ad matching automatically.
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Complete Example
|
|
65
|
+
|
|
66
|
+
Full integration including ad retrieval, display, and click tracking:
|
|
70
67
|
|
|
71
68
|
```typescript
|
|
72
|
-
|
|
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
|
-
|
|
77
|
-
|
|
71
|
+
const client = new AttentionMarketClient({
|
|
72
|
+
apiKey: process.env.ATTENTIONMARKET_API_KEY,
|
|
73
|
+
agentId: 'your_agent_id'
|
|
74
|
+
});
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
```
|
|
76
|
+
async function handleUserMessage(userMessage: string) {
|
|
77
|
+
const ad = await client.decideFromContext({ userMessage });
|
|
82
78
|
|
|
83
|
-
|
|
79
|
+
if (!ad) {
|
|
80
|
+
return null; // No ads available
|
|
81
|
+
}
|
|
84
82
|
|
|
85
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
import { buildTaxonomy } from '@the_ro_show/agent-ads-sdk';
|
|
102
|
+
---
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
// → "insurance.auto.full_coverage.quote"
|
|
103
|
-
```
|
|
104
|
+
## API Reference
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
import { suggestTaxonomies } from '@the_ro_show/agent-ads-sdk';
|
|
106
|
+
### Primary API
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
-
|
|
132
|
+
Records user clicks for revenue attribution. Call this when a user clicks an ad. Handles deduplication and retries automatically.
|
|
127
133
|
|
|
128
|
-
|
|
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
|
-
|
|
140
|
-
'
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
###
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
'
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
'
|
|
167
|
-
'
|
|
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
|
-
|
|
195
|
+
See [TAXONOMY_SYSTEM.md](./TAXONOMY_SYSTEM.md) for all categories.
|
|
171
196
|
|
|
172
197
|
---
|
|
173
198
|
|
|
174
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
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
|
-
|
|
184
|
-
|
|
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
|
-
|
|
188
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
217
|
-
if (decision.status === 'filled') {
|
|
218
|
-
const ad = decision.units[0];
|
|
236
|
+
---
|
|
219
237
|
|
|
220
|
-
|
|
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
|
-
|
|
226
|
-
|
|
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
|
-
|
|
235
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
275
|
+
### 🎨 Response Formatting
|
|
251
276
|
|
|
252
|
-
|
|
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
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
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
|
|
270
|
-
//
|
|
292
|
+
const mention = formatInlineMention(ad);
|
|
293
|
+
// → "Btw, Lemonade offers 20% off for new drivers [Sponsored]"
|
|
271
294
|
```
|
|
272
295
|
|
|
273
|
-
|
|
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:
|
|
278
|
-
decision_id:
|
|
279
|
-
unit_id:
|
|
280
|
-
tracking_token:
|
|
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
|
-
|
|
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:
|
|
289
|
-
decision_id:
|
|
290
|
-
unit_id:
|
|
291
|
-
tracking_token:
|
|
292
|
-
href:
|
|
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
|
-
|
|
340
|
+
---
|
|
297
341
|
|
|
298
|
-
|
|
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
|
-
|
|
344
|
+
#### `createOpportunity()` - Build opportunity objects easily
|
|
345
|
+
Helper to construct the opportunity payload for decide() calls. Handles defaults and validation.
|
|
308
346
|
|
|
309
|
-
|
|
310
|
-
|
|
347
|
+
```typescript
|
|
348
|
+
const opportunity = createOpportunity({
|
|
349
|
+
taxonomy: 'insurance.auto.quote',
|
|
350
|
+
country: 'US'
|
|
351
|
+
});
|
|
352
|
+
```
|
|
311
353
|
|
|
312
|
-
|
|
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
|
-
|
|
366
|
+
### 🧪 Testing
|
|
317
367
|
|
|
318
|
-
|
|
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
|
-
|
|
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
|
-
|
|
338
|
-
|
|
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
|
-
##
|
|
415
|
+
## Using Test vs Live Keys
|
|
345
416
|
|
|
346
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
351
|
-
❌ **Unsafe:** Browser JavaScript, React/Vue components, mobile apps
|
|
433
|
+
---
|
|
352
434
|
|
|
353
|
-
|
|
435
|
+
## Sanitizing Ad Content
|
|
354
436
|
|
|
355
|
-
|
|
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.
|
|
361
|
-
const safeURL = sanitizeURL(ad.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|