@the_ro_show/agent-ads-sdk 0.13.1 → 0.13.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 +299 -605
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,450 +1,242 @@
|
|
|
1
|
-
# AttentionMarket
|
|
1
|
+
# AttentionMarket SDK
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@the_ro_show/agent-ads-sdk)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Monetize your AI application with contextual advertising. AttentionMarket matches user intent with relevant sponsored content, enabling you to generate revenue from every conversation.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Two Ways To Earn
|
|
13
|
-
|
|
14
|
-
### 1. Show ads in your chatbot or AI assistant
|
|
15
|
-
Your app has conversations. Users ask questions. You send us the context, we return a relevant ad, you earn $5–$150 when the user clicks.
|
|
16
|
-
|
|
17
|
-
### 2. List your AI agent on the exchange
|
|
18
|
-
You built a specialized AI agent. Other AI agents need what you offer. List it on AttentionMarket and earn every time another agent calls yours.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Quick Start — 30 Seconds
|
|
23
|
-
|
|
24
|
-
Get your API keys at [api.attentionmarket.ai](https://api.attentionmarket.ai), then:
|
|
8
|
+
## Installation
|
|
25
9
|
|
|
26
10
|
```bash
|
|
27
|
-
|
|
28
|
-
-H "X-AM-API-Key: am_live_YOUR_KEY" \
|
|
29
|
-
-H "Content-Type: application/json" \
|
|
30
|
-
-d '{"context": "I need car insurance"}'
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Response:**
|
|
34
|
-
```json
|
|
35
|
-
{
|
|
36
|
-
"status": "filled",
|
|
37
|
-
"units": [{
|
|
38
|
-
"suggestion": {
|
|
39
|
-
"title": "Get 20% off car insurance",
|
|
40
|
-
"body": "Compare quotes in minutes",
|
|
41
|
-
"cta": "Get a Quote",
|
|
42
|
-
"tracking_url": "https://..."
|
|
43
|
-
}
|
|
44
|
-
}]
|
|
45
|
-
}
|
|
11
|
+
npm install @the_ro_show/agent-ads-sdk
|
|
46
12
|
```
|
|
47
13
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
---
|
|
14
|
+
## Quick Start
|
|
51
15
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
**As of v0.9.0, impression tracking is REQUIRED to earn revenue from clicks.**
|
|
55
|
-
|
|
56
|
-
When you show an ad to a user, you must track an impression. Clicks without prior impressions will:
|
|
57
|
-
- ✅ Still redirect the user to the advertiser (good UX)
|
|
58
|
-
- ❌ NOT charge the advertiser
|
|
59
|
-
- ❌ NOT credit your earnings
|
|
60
|
-
|
|
61
|
-
### Why This Matters
|
|
62
|
-
|
|
63
|
-
This prevents developers from filtering ads client-side and still earning revenue from clicks. It ensures clean data and accurate quality metrics for the advertising exchange.
|
|
64
|
-
|
|
65
|
-
### Using `decideFromContext()` (Recommended)
|
|
16
|
+
```typescript
|
|
17
|
+
import { AttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
|
|
66
18
|
|
|
67
|
-
|
|
19
|
+
const client = new AttentionMarketClient({
|
|
20
|
+
apiKey: 'am_live_YOUR_KEY',
|
|
21
|
+
agentId: 'agt_YOUR_AGENT_ID'
|
|
22
|
+
});
|
|
68
23
|
|
|
69
|
-
|
|
70
|
-
// Impressions tracked automatically ✅
|
|
24
|
+
// Request a contextual ad
|
|
71
25
|
const ad = await client.decideFromContext({
|
|
72
|
-
userMessage: "I
|
|
26
|
+
userMessage: "I'm looking for car insurance",
|
|
73
27
|
placement: 'sponsored_suggestion'
|
|
74
28
|
});
|
|
75
29
|
|
|
76
30
|
if (ad) {
|
|
77
|
-
//
|
|
78
|
-
|
|
31
|
+
console.log(ad.creative.title); // "Get 20% off car insurance"
|
|
32
|
+
console.log(ad.creative.body); // "Compare quotes from top providers"
|
|
33
|
+
console.log(ad.click_url); // Auto-tracked click URL
|
|
79
34
|
}
|
|
80
35
|
```
|
|
81
36
|
|
|
82
|
-
|
|
37
|
+
## Authentication
|
|
83
38
|
|
|
84
|
-
|
|
39
|
+
All API requests require authentication via an API key. Get your keys at [api.attentionmarket.ai](https://api.attentionmarket.ai).
|
|
85
40
|
|
|
86
|
-
|
|
87
|
-
// Step 1: Get ad
|
|
88
|
-
const response = await fetch('https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/decide', {
|
|
89
|
-
method: 'POST',
|
|
90
|
-
headers: { 'X-AM-API-Key': 'am_live_...' },
|
|
91
|
-
body: JSON.stringify({ context: 'I need car insurance' })
|
|
92
|
-
});
|
|
93
|
-
const data = await response.json();
|
|
94
|
-
|
|
95
|
-
if (data.status === 'filled') {
|
|
96
|
-
const ad = data.units[0];
|
|
97
|
-
|
|
98
|
-
// Step 2: Track impression IMMEDIATELY when showing ad ✅
|
|
99
|
-
await fetch('https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/event', {
|
|
100
|
-
method: 'POST',
|
|
101
|
-
headers: { 'X-AM-API-Key': 'am_live_...' },
|
|
102
|
-
body: JSON.stringify({
|
|
103
|
-
event_id: `evt_${crypto.randomUUID()}`,
|
|
104
|
-
event_type: 'impression',
|
|
105
|
-
occurred_at: new Date().toISOString(),
|
|
106
|
-
agent_id: 'YOUR_AGENT_ID',
|
|
107
|
-
unit_id: ad.unit_id,
|
|
108
|
-
tracking_token: ad.tracking.token
|
|
109
|
-
})
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// Step 3: Now safe to show ad and earn from clicks
|
|
113
|
-
displayAd(ad);
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Use Case 1: Monetize Your Chatbot or AI Assistant
|
|
120
|
-
|
|
121
|
-
Any app with conversations can earn revenue. Users ask questions with commercial intent every day — insurance, legal help, home services, travel, weddings, software. When they do, you can surface a relevant offer and earn.
|
|
122
|
-
|
|
123
|
-
**Platforms this works on:**
|
|
41
|
+
### API Key Types
|
|
124
42
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
| **AI Assistants** | Mobile AI apps, productivity tools, personal assistants |
|
|
128
|
-
| **Chatbots** | Website chat, customer service bots, FAQ bots |
|
|
129
|
-
| **Messaging Bots** | WhatsApp, Discord, Telegram, Slack |
|
|
130
|
-
| **Voice Assistants** | Alexa Skills, Google Actions, voice apps |
|
|
131
|
-
| **AI Companions** | Coaching bots, tutors, entertainment assistants |
|
|
43
|
+
- **Test keys** (`am_test_...`) — Use in development. No charges, test data only.
|
|
44
|
+
- **Live keys** (`am_live_...`) — Use in production. Real advertisers, real revenue.
|
|
132
45
|
|
|
133
|
-
###
|
|
46
|
+
### For Autonomous AI Agents (Clawdbots)
|
|
134
47
|
|
|
135
|
-
|
|
136
|
-
User sends message → You call our API with context → We return a relevant ad
|
|
137
|
-
→ You show it → User clicks → You earn $5–$150
|
|
138
|
-
```
|
|
48
|
+
If you're building an autonomous agent with email access, you can set up AttentionMarket programmatically:
|
|
139
49
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
**iOS (Swift)** — drop this into your Xcode project:
|
|
143
|
-
```swift
|
|
144
|
-
// Initialize once
|
|
145
|
-
let client = AttentionMarketClient(
|
|
146
|
-
apiKey: "am_live_YOUR_KEY",
|
|
147
|
-
agentId: "agt_YOUR_ID"
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
// Call after your AI responds
|
|
151
|
-
if let ad = await client.getAd(for: userMessage) {
|
|
152
|
-
showAdInChat(
|
|
153
|
-
title: ad.suggestion.title,
|
|
154
|
-
body: ad.suggestion.body,
|
|
155
|
-
cta: ad.suggestion.cta,
|
|
156
|
-
url: ad.suggestion.trackingUrl
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
[Full iOS example →](./examples/ios/AttentionMarketClient.swift)
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
**Android (Kotlin)**:
|
|
165
|
-
```kotlin
|
|
166
|
-
val client = AttentionMarketClient(
|
|
167
|
-
apiKey = "am_live_YOUR_KEY",
|
|
168
|
-
agentId = "agt_YOUR_ID"
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
client.getAd(context = userMessage)?.let { ad ->
|
|
172
|
-
showAdInChat(
|
|
173
|
-
title = ad.suggestion.title,
|
|
174
|
-
body = ad.suggestion.body,
|
|
175
|
-
url = ad.suggestion.trackingUrl
|
|
176
|
-
)
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
[Full Android example →](./examples/android/AttentionMarketClient.kt)
|
|
50
|
+
#### Email-Based Autonomous Setup
|
|
180
51
|
|
|
181
|
-
|
|
52
|
+
1. **Sign up** at https://api.attentionmarket.ai/api/login
|
|
53
|
+
2. **Monitor your inbox** for verification email from `noreply@worldview.network`
|
|
54
|
+
3. **Extract verification link** from email body:
|
|
55
|
+
```
|
|
56
|
+
https://gleam-start-page.lovable.app/api/verify-email?token={token}
|
|
57
|
+
```
|
|
58
|
+
4. **Visit the link** programmatically to verify your account
|
|
59
|
+
5. **Login and retrieve credentials:**
|
|
182
60
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
61
|
+
```typescript
|
|
62
|
+
// Login to get session
|
|
63
|
+
const loginResponse = await fetch('https://api.attentionmarket.ai/api/login', {
|
|
186
64
|
method: 'POST',
|
|
187
|
-
headers: {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
65
|
+
headers: { 'Content-Type': 'application/json' },
|
|
66
|
+
body: JSON.stringify({
|
|
67
|
+
email: 'your-agent@example.com',
|
|
68
|
+
password: 'your_password'
|
|
69
|
+
})
|
|
192
70
|
});
|
|
193
71
|
|
|
194
|
-
const
|
|
72
|
+
const sessionCookie = loginResponse.headers.get('set-cookie');
|
|
195
73
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
[Full Web example →](./examples/web/attentionmarket.js)
|
|
202
|
-
|
|
203
|
-
---
|
|
74
|
+
// Fetch API credentials
|
|
75
|
+
const credsResponse = await fetch('https://api.attentionmarket.ai/developer-data', {
|
|
76
|
+
headers: { 'Cookie': sessionCookie }
|
|
77
|
+
});
|
|
204
78
|
|
|
205
|
-
|
|
206
|
-
```bash
|
|
207
|
-
npm install @the_ro_show/agent-ads-sdk
|
|
208
|
-
```
|
|
209
|
-
```javascript
|
|
210
|
-
import { AttentionMarketClient } from '@the_ro_show/agent-ads-sdk';
|
|
79
|
+
const { api_key, agent_id } = await credsResponse.json();
|
|
211
80
|
|
|
81
|
+
// Initialize SDK
|
|
212
82
|
const client = new AttentionMarketClient({
|
|
213
|
-
apiKey:
|
|
214
|
-
agentId:
|
|
83
|
+
apiKey: api_key, // am_test_...
|
|
84
|
+
agentId: agent_id // agt_...
|
|
215
85
|
});
|
|
216
|
-
|
|
217
|
-
const ad = await client.decideFromContext({ userMessage });
|
|
218
|
-
if (ad) console.log(ad.creative.title, ad.click_url);
|
|
219
86
|
```
|
|
220
87
|
|
|
221
|
-
|
|
88
|
+
**Complete autonomous flow:** Sign up → Verify email → Retrieve credentials → Install SDK → Start earning revenue
|
|
222
89
|
|
|
223
|
-
|
|
90
|
+
📖 **[Full Personal AI Agent Setup Guide](https://docs.attentionmarket.ai/personal-agents)**
|
|
224
91
|
|
|
225
|
-
|
|
92
|
+
### SDK Configuration
|
|
226
93
|
|
|
227
|
-
|
|
94
|
+
```typescript
|
|
95
|
+
const client = new AttentionMarketClient({
|
|
96
|
+
apiKey: 'am_live_YOUR_KEY', // Required
|
|
97
|
+
agentId: 'agt_YOUR_AGENT_ID', // Required for decideFromContext()
|
|
98
|
+
baseUrl: 'https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1', // Optional: defaults to production
|
|
99
|
+
timeoutMs: 4000, // Optional: request timeout in milliseconds
|
|
100
|
+
maxRetries: 2 // Optional: automatic retry count
|
|
101
|
+
});
|
|
102
|
+
```
|
|
228
103
|
|
|
229
|
-
|
|
104
|
+
## Core Concepts
|
|
230
105
|
|
|
231
|
-
|
|
232
|
-
General assistant encounters a task it can't handle well
|
|
233
|
-
→ Calls AttentionMarket with context + response_type: "agent"
|
|
234
|
-
→ Exchange returns the best specialized agent for that task
|
|
235
|
-
→ General assistant calls your agent
|
|
236
|
-
→ You earn per call
|
|
237
|
-
```
|
|
106
|
+
### Placements
|
|
238
107
|
|
|
239
|
-
|
|
108
|
+
A placement defines where ads appear in your application:
|
|
240
109
|
|
|
241
|
-
|
|
110
|
+
- `sponsored_suggestion` — Conversational ad in chat flow (most common)
|
|
111
|
+
- `sponsored_block` — Dedicated ad section in UI
|
|
112
|
+
- `sponsored_tool` — AI agent service recommendation
|
|
242
113
|
|
|
243
|
-
|
|
244
|
-
```bash
|
|
245
|
-
curl -X POST https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/decide \
|
|
246
|
-
-H "X-AM-API-Key: am_live_DEV_A_KEY" \
|
|
247
|
-
-H "Content-Type: application/json" \
|
|
248
|
-
-d '{
|
|
249
|
-
"context": "User needs a wedding photographer in Austin under $3,000",
|
|
250
|
-
"response_type": "agent"
|
|
251
|
-
}'
|
|
252
|
-
```
|
|
114
|
+
### Ad Response Format
|
|
253
115
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
116
|
+
```typescript
|
|
117
|
+
interface AdResponse {
|
|
118
|
+
request_id: string;
|
|
119
|
+
decision_id: string;
|
|
120
|
+
advertiser_id: string;
|
|
121
|
+
ad_type: 'link' | 'recommendation' | 'service';
|
|
122
|
+
payout: number; // Amount earned on conversion (in cents)
|
|
123
|
+
|
|
124
|
+
creative: {
|
|
125
|
+
title: string;
|
|
126
|
+
body: string;
|
|
127
|
+
cta: string;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
click_url: string; // Tracked click URL (use this)
|
|
131
|
+
tracking_url?: string; // Server-side tracking URL
|
|
132
|
+
tracking_token: string; // For manual event tracking
|
|
133
|
+
|
|
134
|
+
disclosure: {
|
|
135
|
+
label: string;
|
|
136
|
+
explanation: string;
|
|
137
|
+
sponsor_name: string;
|
|
138
|
+
};
|
|
268
139
|
}
|
|
269
140
|
```
|
|
270
141
|
|
|
271
|
-
|
|
272
|
-
**Developer B** earns per call. **Developer A** earns a routing fee.
|
|
273
|
-
|
|
274
|
-
### List Your Agent
|
|
275
|
-
|
|
276
|
-
Sign up as an advertiser at [api.attentionmarket.ai](https://api.attentionmarket.ai) and create an **Agent Ad** campaign:
|
|
277
|
-
|
|
278
|
-
| Field | Description |
|
|
279
|
-
|-------|-------------|
|
|
280
|
-
| Agent Name | Display name (e.g. "WeddingPhoto AI") |
|
|
281
|
-
| What does your agent do? | Natural language capability description — used for matching |
|
|
282
|
-
| Endpoint URL | Where calling agents send requests |
|
|
283
|
-
| What to send | Input format description |
|
|
284
|
-
| What you return | Output format description |
|
|
285
|
-
| Bid per call | What you pay each time your agent is called |
|
|
286
|
-
|
|
287
|
-
**Matching is semantic** — describe your agent clearly in plain English and we handle the rest.
|
|
142
|
+
### Impression Tracking
|
|
288
143
|
|
|
289
|
-
|
|
144
|
+
**Important:** As of v0.9.0, impression tracking is required to earn revenue from clicks.
|
|
290
145
|
|
|
291
|
-
|
|
146
|
+
The SDK automatically tracks impressions when using `decideFromContext()`. Clicks without prior impressions will redirect users but will not generate revenue.
|
|
292
147
|
|
|
293
|
-
|
|
148
|
+
If using the raw `decide()` API, you must manually track impressions:
|
|
294
149
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|---------------------|------------|-----------------|
|
|
305
|
-
| 50 | $50 | $2,500 |
|
|
306
|
-
| 200 | $50 | $10,000 |
|
|
307
|
-
| 1,000 | $50 | $50,000 |
|
|
308
|
-
|
|
309
|
-
### As an Agent Advertiser (listing your agent)
|
|
150
|
+
```typescript
|
|
151
|
+
await client.trackImpression({
|
|
152
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
153
|
+
request_id: ad.request_id,
|
|
154
|
+
decision_id: ad.decision_id,
|
|
155
|
+
unit_id: ad._ad.unit_id,
|
|
156
|
+
tracking_token: ad.tracking_token
|
|
157
|
+
});
|
|
158
|
+
```
|
|
310
159
|
|
|
311
|
-
|
|
312
|
-
- Second-price auction — you bid a max, you often pay less
|
|
313
|
-
- Full budget controls — set a cap, campaign pauses when spent
|
|
314
|
-
- Track spend and performance in the advertiser dashboard
|
|
160
|
+
## Developer Controls
|
|
315
161
|
|
|
316
|
-
|
|
162
|
+
AttentionMarket provides fine-grained controls over ad selection, quality, and revenue optimization.
|
|
317
163
|
|
|
318
|
-
|
|
164
|
+
### Quality and Brand Safety
|
|
319
165
|
|
|
320
|
-
|
|
166
|
+
#### Minimum Quality Score
|
|
321
167
|
|
|
322
|
-
|
|
168
|
+
Filter ads based on historical performance metrics. Quality scores range from 0.0 (worst) to 1.0 (best) and are calculated from click-through rates, conversion rates, and user feedback.
|
|
323
169
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- ❌ Wrong positive prediction → **-5% penalty**
|
|
331
|
-
- 🤷 Neutral/negative → no bonus/penalty (data only)
|
|
170
|
+
```typescript
|
|
171
|
+
const ad = await client.decideFromContext({
|
|
172
|
+
userMessage: "I need legal help",
|
|
173
|
+
minQualityScore: 0.7 // Only show ads with quality >= 0.7
|
|
174
|
+
});
|
|
175
|
+
```
|
|
332
176
|
|
|
333
|
-
|
|
177
|
+
**Validation:** Must be a number between 0.0 and 1.0.
|
|
334
178
|
|
|
335
|
-
**
|
|
336
|
-
-
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
- Harder to game (can't spam "positive" on everything)
|
|
179
|
+
**Use cases:**
|
|
180
|
+
- Premium applications: `0.8+` for high-quality experiences only
|
|
181
|
+
- Brand-sensitive contexts: `0.7+` to avoid low-quality advertisers
|
|
182
|
+
- General applications: `0.5+` for balanced quality and fill rate
|
|
340
183
|
|
|
341
|
-
|
|
184
|
+
#### Category Filtering
|
|
342
185
|
|
|
343
|
-
|
|
186
|
+
Control which advertiser categories can appear using the IAB Content Taxonomy 3.0 (704 categories across 38 top-level verticals).
|
|
344
187
|
|
|
345
|
-
|
|
346
|
-
- Spamming fake positive responses = net loss
|
|
347
|
-
- Accuracy = net gain (bonus > penalty when right)
|
|
348
|
-
- System rewards honest data collection
|
|
188
|
+
##### Allowed Categories
|
|
349
189
|
|
|
350
|
-
|
|
190
|
+
Whitelist specific categories. Only ads from these categories will be shown.
|
|
351
191
|
|
|
352
192
|
```typescript
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
193
|
+
// Insurance comparison app: only show insurance ads
|
|
194
|
+
const ad = await client.decideFromContext({
|
|
195
|
+
userMessage: "I need car insurance",
|
|
196
|
+
allowedCategories: [31] // 31 = Auto Insurance (IAB category)
|
|
357
197
|
});
|
|
358
198
|
|
|
359
|
-
//
|
|
199
|
+
// Wedding planner: allow wedding + photography + food
|
|
360
200
|
const ad = await client.decideFromContext({
|
|
361
|
-
userMessage: "
|
|
201
|
+
userMessage: "Help me plan my wedding",
|
|
202
|
+
allowedCategories: [
|
|
203
|
+
603, // Weddings
|
|
204
|
+
162, // Photography
|
|
205
|
+
190 // Restaurants
|
|
206
|
+
]
|
|
362
207
|
});
|
|
363
|
-
|
|
364
|
-
if (ad) {
|
|
365
|
-
// User responds after clicking
|
|
366
|
-
const userResponse = "This looks perfect! How do I sign up?";
|
|
367
|
-
|
|
368
|
-
await client.sendFeedback({
|
|
369
|
-
tracking_token: ad.tracking_token,
|
|
370
|
-
user_response: userResponse,
|
|
371
|
-
agent_response: "Here's the signup link...",
|
|
372
|
-
additional_context: "User spent 2 minutes on offer page"
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
// AI will detect positive sentiment → +15% bonus if user converts
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### HTTP Example
|
|
380
|
-
|
|
381
|
-
```bash
|
|
382
|
-
curl -X POST https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/feedback \
|
|
383
|
-
-H "X-AM-API-Key: am_live_YOUR_KEY" \
|
|
384
|
-
-H "Content-Type: application/json" \
|
|
385
|
-
-d '{
|
|
386
|
-
"tracking_token": "eyJhbGc...",
|
|
387
|
-
"user_response": "This looks great! How do I get started?",
|
|
388
|
-
"agent_response": "Here is the signup process...",
|
|
389
|
-
"additional_context": "User asked 3 follow-up questions"
|
|
390
|
-
}'
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
**Response:**
|
|
394
|
-
```json
|
|
395
|
-
{
|
|
396
|
-
"success": true,
|
|
397
|
-
"sentiment_detected": "positive",
|
|
398
|
-
"potential_bonus": "$1.05",
|
|
399
|
-
"potential_penalty": "$0.35",
|
|
400
|
-
"message": "Feedback recorded! Detected sentiment: positive. If correct (user converts within 7 days), you'll earn a +15% bonus. Wrong predictions incur a -5% penalty.",
|
|
401
|
-
"resolution_date": "2026-02-28T12:00:00Z"
|
|
402
|
-
}
|
|
403
208
|
```
|
|
404
209
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
**Good signals to capture:**
|
|
408
|
-
- User's actual text responses after clicking
|
|
409
|
-
- Your agent's follow-up messages
|
|
410
|
-
- Context about how long user engaged with the offer
|
|
411
|
-
- Any follow-up questions or actions
|
|
210
|
+
##### Blocked Categories
|
|
412
211
|
|
|
413
|
-
|
|
414
|
-
- Send actual user text, not summaries
|
|
415
|
-
- Include your agent's response for context
|
|
416
|
-
- Only send when you have meaningful interaction data
|
|
417
|
-
- Quality > quantity
|
|
418
|
-
|
|
419
|
-
---
|
|
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:
|
|
212
|
+
Blacklist specific categories. Ads from these categories will never be shown.
|
|
428
213
|
|
|
429
214
|
```typescript
|
|
215
|
+
// Block all sensitive content (gambling, adult, controversial)
|
|
430
216
|
const ad = await client.decideFromContext({
|
|
431
|
-
userMessage: "
|
|
432
|
-
|
|
217
|
+
userMessage: "Help me with something",
|
|
218
|
+
blockedCategories: [601] // Blocks "Sensitive Topics" + all children
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Legal assistant: block competitor law firms
|
|
222
|
+
const ad = await client.decideFromContext({
|
|
223
|
+
userMessage: "I need legal help",
|
|
224
|
+
blockedCategories: [318] // Block "Legal Services"
|
|
433
225
|
});
|
|
434
226
|
```
|
|
435
227
|
|
|
436
|
-
**
|
|
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
|
|
228
|
+
**Parent-child relationships:** Blocking a parent category automatically blocks all subcategories. For example, blocking category `1` (Automotive) blocks Auto Insurance, Auto Repair, Auto Parts, etc.
|
|
440
229
|
|
|
441
|
-
|
|
230
|
+
**Precedence:** If `allowedCategories` is set, `blockedCategories` is ignored.
|
|
442
231
|
|
|
443
|
-
|
|
232
|
+
**Validation rules:**
|
|
233
|
+
- `allowedCategories`: Must be a non-empty array of numbers or strings
|
|
234
|
+
- `blockedCategories`: Must be an array of numbers or strings
|
|
235
|
+
- Empty `allowedCategories: []` is rejected (would block all ads)
|
|
444
236
|
|
|
445
|
-
**
|
|
237
|
+
**Note:** IAB category IDs (numbers) are recommended. Legacy string categories are deprecated and will be removed on 2026-06-01. Use the `getCategories()` API to discover category IDs.
|
|
446
238
|
|
|
447
|
-
|
|
239
|
+
##### Discovering Categories
|
|
448
240
|
|
|
449
241
|
```typescript
|
|
450
242
|
// Get all 38 top-level categories
|
|
@@ -466,55 +258,9 @@ insurance.categories.forEach(cat => {
|
|
|
466
258
|
// Output: "Automotive > Auto Insurance", "Personal Finance > Insurance", etc.
|
|
467
259
|
```
|
|
468
260
|
|
|
469
|
-
####
|
|
261
|
+
#### Advertiser Blocklist
|
|
470
262
|
|
|
471
|
-
|
|
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:
|
|
263
|
+
Block specific advertisers by ID (e.g., based on user feedback or competitive conflicts).
|
|
518
264
|
|
|
519
265
|
```typescript
|
|
520
266
|
const ad = await client.decideFromContext({
|
|
@@ -523,292 +269,240 @@ const ad = await client.decideFromContext({
|
|
|
523
269
|
});
|
|
524
270
|
```
|
|
525
271
|
|
|
526
|
-
|
|
272
|
+
**Validation:** Must be an array of non-empty strings (advertiser IDs).
|
|
527
273
|
|
|
528
|
-
|
|
274
|
+
Advertiser IDs are included in ad responses as `advertiser_id`.
|
|
529
275
|
|
|
530
|
-
|
|
276
|
+
### Revenue Optimization
|
|
531
277
|
|
|
532
|
-
|
|
278
|
+
#### Minimum CPC Filter
|
|
533
279
|
|
|
534
|
-
Only show ads above a
|
|
280
|
+
Only show ads with bids at or above a specified cost-per-click threshold (in cents).
|
|
535
281
|
|
|
536
282
|
```typescript
|
|
537
283
|
const ad = await client.decideFromContext({
|
|
538
284
|
userMessage: "I need car insurance",
|
|
539
|
-
minCPC: 100 // Only ads bidding
|
|
285
|
+
minCPC: 100 // Only ads bidding >= $1.00 per click
|
|
540
286
|
});
|
|
541
287
|
```
|
|
542
288
|
|
|
289
|
+
**Validation:** Must be a non-negative number.
|
|
290
|
+
|
|
543
291
|
**Use cases:**
|
|
544
|
-
-
|
|
545
|
-
-
|
|
546
|
-
-
|
|
292
|
+
- Premium applications: `200+` for $2+ ads only
|
|
293
|
+
- High-value verticals: Filter out low-budget advertisers
|
|
294
|
+
- Revenue targets: Ensure minimum revenue per impression
|
|
295
|
+
- Lower fill rate tolerance: When you'd rather show nothing than a low-value ad
|
|
296
|
+
|
|
297
|
+
**Trade-off:** Higher thresholds = higher revenue per ad but lower fill rate.
|
|
547
298
|
|
|
548
|
-
|
|
299
|
+
#### Minimum Relevance Score
|
|
549
300
|
|
|
550
|
-
Only show ads
|
|
301
|
+
Only show ads with semantic similarity at or above a threshold. Relevance scores range from 0.0 (unrelated) to 1.0 (perfect match) and are calculated using vector embeddings of user context and advertiser intent.
|
|
551
302
|
|
|
552
303
|
```typescript
|
|
553
304
|
const ad = await client.decideFromContext({
|
|
554
305
|
userMessage: "Help me plan my wedding",
|
|
555
|
-
minRelevanceScore: 0.8 // Only highly relevant ads
|
|
306
|
+
minRelevanceScore: 0.8 // Only highly relevant ads
|
|
556
307
|
});
|
|
557
308
|
```
|
|
558
309
|
|
|
310
|
+
**Validation:** Must be a number between 0.0 and 1.0.
|
|
311
|
+
|
|
559
312
|
**Use cases:**
|
|
560
|
-
-
|
|
561
|
-
-
|
|
562
|
-
-
|
|
563
|
-
-
|
|
313
|
+
- Niche applications: `0.8+` for specialized content only (e.g., legal assistant)
|
|
314
|
+
- User experience priority: Filter out loosely related ads
|
|
315
|
+
- Context-sensitive placements: Ensure ads match conversation topic
|
|
316
|
+
- Brand-aligned content: Maintain thematic consistency
|
|
317
|
+
|
|
318
|
+
**Important:** This filter only applies to campaigns with semantic targeting. Keyword and automatic campaigns are not affected.
|
|
564
319
|
|
|
565
|
-
|
|
320
|
+
**Default threshold:** Backend applies a minimum threshold of 0.25 for all semantic campaigns (ads below this are never shown).
|
|
566
321
|
|
|
567
|
-
|
|
322
|
+
#### Ranking Strategy
|
|
323
|
+
|
|
324
|
+
Choose how ads are ranked when multiple ads match the request.
|
|
568
325
|
|
|
569
326
|
```typescript
|
|
570
|
-
//
|
|
327
|
+
// Revenue-optimized (default): highest bid wins
|
|
571
328
|
const ad = await client.decideFromContext({
|
|
572
329
|
userMessage: "I need legal help",
|
|
573
330
|
optimizeFor: 'revenue' // Rank by bid × quality × relevance
|
|
574
331
|
});
|
|
575
332
|
|
|
576
|
-
//
|
|
333
|
+
// Relevance-optimized: best match wins
|
|
577
334
|
const ad = await client.decideFromContext({
|
|
578
335
|
userMessage: "I need legal help",
|
|
579
336
|
optimizeFor: 'relevance' // Rank by semantic similarity only
|
|
580
337
|
});
|
|
581
338
|
```
|
|
582
339
|
|
|
583
|
-
**
|
|
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
|
|
340
|
+
**Validation:** Must be either `'revenue'` or `'relevance'`.
|
|
587
341
|
|
|
588
342
|
**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
343
|
|
|
594
|
-
**
|
|
595
|
-
-
|
|
596
|
-
-
|
|
597
|
-
-
|
|
344
|
+
- **Revenue mode:** Winner is ranked by composite score (bid × quality × relevance), pays just enough to beat the next ad's composite score + $0.01
|
|
345
|
+
- **Relevance mode:** Winner is ranked by semantic similarity, pays just enough to beat the next ad in composite score space + $0.01
|
|
346
|
+
- **Price cap:** Winner never pays more than their max bid (auction integrity guaranteed)
|
|
347
|
+
- **Price floor:** Minimum clearing price of $0.25 ensures platform sustainability
|
|
348
|
+
|
|
349
|
+
**Use cases:**
|
|
350
|
+
- General applications: `'revenue'` to maximize earnings
|
|
351
|
+
- Niche applications: `'relevance'` to prioritize perfect matches over high bids
|
|
352
|
+
- Premium experiences: Combine with high `minRelevanceScore` + `'relevance'` ranking
|
|
353
|
+
|
|
354
|
+
#### Combined Controls
|
|
598
355
|
|
|
599
|
-
|
|
356
|
+
Combine multiple controls for precise ad selection:
|
|
600
357
|
|
|
601
358
|
```typescript
|
|
602
|
-
// Premium legal assistant:
|
|
359
|
+
// Premium legal assistant: high relevance + high bids + category filter
|
|
603
360
|
const ad = await client.decideFromContext({
|
|
604
361
|
userMessage: "I need estate planning help",
|
|
605
|
-
minRelevanceScore: 0.8,
|
|
606
|
-
minCPC: 200,
|
|
607
|
-
|
|
608
|
-
|
|
362
|
+
minRelevanceScore: 0.8, // Only highly relevant
|
|
363
|
+
minCPC: 200, // Only $2+ bids
|
|
364
|
+
minQualityScore: 0.7, // Only high-quality advertisers
|
|
365
|
+
optimizeFor: 'relevance', // Best match wins
|
|
366
|
+
allowedCategories: [318] // Legal services only
|
|
609
367
|
});
|
|
368
|
+
```
|
|
610
369
|
|
|
611
|
-
|
|
370
|
+
## Advanced Features
|
|
371
|
+
|
|
372
|
+
### Multi-Turn Conversations
|
|
373
|
+
|
|
374
|
+
Include conversation history for better ad matching:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
612
377
|
const ad = await client.decideFromContext({
|
|
613
|
-
userMessage: "
|
|
614
|
-
|
|
615
|
-
|
|
378
|
+
userMessage: "What are my options?",
|
|
379
|
+
conversationHistory: [
|
|
380
|
+
"User: My car insurance is too expensive",
|
|
381
|
+
"Agent: I can help you compare rates",
|
|
382
|
+
"User: What are my options?"
|
|
383
|
+
]
|
|
616
384
|
});
|
|
617
385
|
```
|
|
618
386
|
|
|
619
|
-
|
|
387
|
+
The SDK automatically limits history to the last 5 messages to prevent token overflow.
|
|
620
388
|
|
|
621
|
-
|
|
389
|
+
### Geographic and Platform Targeting
|
|
622
390
|
|
|
623
391
|
```typescript
|
|
624
392
|
const ad = await client.decideFromContext({
|
|
625
393
|
userMessage: "I need car insurance",
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
|
394
|
+
country: 'US',
|
|
395
|
+
language: 'en',
|
|
396
|
+
platform: 'ios' // 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other'
|
|
633
397
|
});
|
|
634
398
|
```
|
|
635
399
|
|
|
636
|
-
###
|
|
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
|
-
|
|
670
|
-
## API Reference
|
|
671
|
-
|
|
672
|
-
### `POST /v1/decide`
|
|
673
|
-
|
|
674
|
-
**Base URL:** `https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/decide`
|
|
400
|
+
### Click Tracking
|
|
675
401
|
|
|
676
|
-
|
|
402
|
+
Clicks are automatically tracked when users visit `click_url`. For manual tracking:
|
|
677
403
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
404
|
+
```typescript
|
|
405
|
+
await client.trackClick({
|
|
406
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
407
|
+
request_id: ad.request_id,
|
|
408
|
+
decision_id: ad.decision_id,
|
|
409
|
+
unit_id: ad._ad.unit_id,
|
|
410
|
+
tracking_token: ad.tracking_token,
|
|
411
|
+
href: ad.click_url,
|
|
412
|
+
click_context: "User clicked 'Get a Quote' button"
|
|
413
|
+
});
|
|
684
414
|
```
|
|
685
415
|
|
|
686
|
-
|
|
416
|
+
Simplified tracking from ad object:
|
|
687
417
|
|
|
688
|
-
```
|
|
689
|
-
{
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
"language": "en",
|
|
693
|
-
"platform": "ios"
|
|
694
|
-
}
|
|
418
|
+
```typescript
|
|
419
|
+
await client.trackClickFromAd(ad, {
|
|
420
|
+
click_context: "User clicked on sponsored suggestion"
|
|
421
|
+
});
|
|
695
422
|
```
|
|
696
423
|
|
|
697
|
-
###
|
|
424
|
+
### Conversion Tracking
|
|
698
425
|
|
|
699
|
-
|
|
700
|
-
{
|
|
701
|
-
"context": "User needs a wedding photographer in Austin",
|
|
702
|
-
"response_type": "agent"
|
|
703
|
-
}
|
|
704
|
-
```
|
|
426
|
+
Track conversions (purchases, signups, etc.) to improve advertiser ROI and your quality score:
|
|
705
427
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
428
|
+
```typescript
|
|
429
|
+
await client.track({
|
|
430
|
+
event_id: `evt_${generateUUID()}`,
|
|
431
|
+
event_type: 'conversion',
|
|
432
|
+
occurred_at: new Date().toISOString(),
|
|
433
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
434
|
+
request_id: ad.request_id,
|
|
435
|
+
decision_id: ad.decision_id,
|
|
436
|
+
unit_id: ad._ad.unit_id,
|
|
437
|
+
tracking_token: ad.tracking_token,
|
|
438
|
+
metadata: {
|
|
439
|
+
conversion_value: 99.99,
|
|
440
|
+
conversion_type: 'purchase'
|
|
441
|
+
}
|
|
442
|
+
});
|
|
719
443
|
```
|
|
720
444
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
```json
|
|
724
|
-
{
|
|
725
|
-
"request_id": "req_abc123",
|
|
726
|
-
"decision_id": "dec_xyz789",
|
|
727
|
-
"status": "filled",
|
|
728
|
-
"ttl_ms": 300000,
|
|
729
|
-
"units": [{
|
|
730
|
-
"unit_id": "unit_123",
|
|
731
|
-
"suggestion": {
|
|
732
|
-
"title": "Get 20% off car insurance",
|
|
733
|
-
"body": "Compare quotes in minutes",
|
|
734
|
-
"cta": "Get a Quote",
|
|
735
|
-
"tracking_url": "https://.../track-click/...",
|
|
736
|
-
"action_url": "https://progressive.com/quote"
|
|
737
|
-
},
|
|
738
|
-
"tracking": {
|
|
739
|
-
"token": "trk_abc",
|
|
740
|
-
"impression_url": "https://.../event",
|
|
741
|
-
"click_url": "https://.../click/trk_abc"
|
|
742
|
-
}
|
|
743
|
-
}]
|
|
744
|
-
}
|
|
745
|
-
```
|
|
445
|
+
## Error Handling
|
|
746
446
|
|
|
747
|
-
|
|
447
|
+
The SDK throws errors for invalid configurations and failed requests:
|
|
748
448
|
|
|
749
|
-
```
|
|
750
|
-
{
|
|
751
|
-
|
|
752
|
-
|
|
449
|
+
```typescript
|
|
450
|
+
try {
|
|
451
|
+
const ad = await client.decideFromContext({
|
|
452
|
+
userMessage: "I need car insurance",
|
|
453
|
+
minQualityScore: -0.5 // Invalid: must be 0.0-1.0
|
|
454
|
+
});
|
|
455
|
+
} catch (error) {
|
|
456
|
+
console.error(error.message);
|
|
457
|
+
// Output: "minQualityScore must be a number between 0.0 and 1.0"
|
|
753
458
|
}
|
|
754
459
|
```
|
|
755
460
|
|
|
756
|
-
###
|
|
461
|
+
### Validation Errors
|
|
757
462
|
|
|
758
|
-
|
|
759
|
-
|-------|-----|
|
|
760
|
-
| `status` | `"filled"` or `"no_fill"` |
|
|
761
|
-
| `suggestion.title` | Ad headline to show |
|
|
762
|
-
| `suggestion.body` | Ad description to show |
|
|
763
|
-
| `suggestion.cta` | Button text |
|
|
764
|
-
| `suggestion.tracking_url` | **Send users here on click** — tracks automatically |
|
|
765
|
-
| `suggestion.action_url` | Direct advertiser URL (display only, no tracking) |
|
|
463
|
+
The SDK validates all parameters before making API calls. Common validation errors:
|
|
766
464
|
|
|
767
|
-
|
|
465
|
+
- `minQualityScore must be a number between 0.0 and 1.0`
|
|
466
|
+
- `minCPC must be a non-negative number (cost-per-click in cents)`
|
|
467
|
+
- `minRelevanceScore must be a number between 0.0 and 1.0`
|
|
468
|
+
- `optimizeFor must be either "revenue" or "relevance"`
|
|
469
|
+
- `allowedCategories cannot be empty (would block all ads). Use blockedCategories to exclude specific categories, or omit to allow all.`
|
|
470
|
+
- `blockedAdvertisers must contain non-empty strings (advertiser IDs)`
|
|
768
471
|
|
|
769
|
-
### HTTP
|
|
472
|
+
### HTTP Errors
|
|
770
473
|
|
|
771
|
-
|
|
772
|
-
|------|---------|
|
|
773
|
-
| `200` | Success — check `status` field |
|
|
774
|
-
| `400` | Bad request — missing `context` field |
|
|
775
|
-
| `401` | Invalid API key |
|
|
776
|
-
| `429` | Rate limit exceeded (1,000 req/min) — retry after 60s |
|
|
777
|
-
| `500` | Server error — retry with backoff |
|
|
474
|
+
The API returns standard HTTP status codes:
|
|
778
475
|
|
|
779
|
-
|
|
476
|
+
- `400 Bad Request` — Invalid parameters (see error message for details)
|
|
477
|
+
- `401 Unauthorized` — Missing or invalid API key
|
|
478
|
+
- `429 Too Many Requests` — Rate limit exceeded
|
|
479
|
+
- `500 Internal Server Error` — Server error (contact support if persistent)
|
|
780
480
|
|
|
781
|
-
##
|
|
481
|
+
## Rate Limits
|
|
782
482
|
|
|
783
|
-
|
|
483
|
+
- **Per IP:** 60 requests per minute
|
|
484
|
+
- **Per API key:** 100 requests per minute
|
|
784
485
|
|
|
785
|
-
|
|
786
|
-
```bash
|
|
787
|
-
node test-integration.js # Tests connectivity and credentials
|
|
788
|
-
node validate-production.js # Full production readiness check (4/4 ✅)
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
Download: [test-integration.js](./test-integration.js) | [validate-production.js](./validate-production.js)
|
|
486
|
+
Rate limits are enforced to prevent abuse and ensure fair resource allocation. If you need higher limits, contact support.
|
|
792
487
|
|
|
793
|
-
|
|
488
|
+
## Testing
|
|
794
489
|
|
|
795
|
-
|
|
490
|
+
Use test API keys (`am_test_...`) for development and testing. Test keys:
|
|
796
491
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
492
|
+
- Return test ads with realistic data
|
|
493
|
+
- Do not charge advertisers
|
|
494
|
+
- Do not generate real revenue
|
|
495
|
+
- Have the same rate limits as live keys
|
|
801
496
|
|
|
802
|
-
|
|
497
|
+
Switch to live keys (`am_live_...`) when deploying to production.
|
|
803
498
|
|
|
804
499
|
## Support
|
|
805
500
|
|
|
806
|
-
- **
|
|
807
|
-
- **
|
|
501
|
+
- **Documentation:** [docs.attentionmarket.ai](https://docs.attentionmarket.ai)
|
|
502
|
+
- **API Reference:** [api.attentionmarket.ai/docs](https://api.attentionmarket.ai/docs)
|
|
503
|
+
- **Issues:** [github.com/rtrivedi/agent-ads-sdk/issues](https://github.com/rtrivedi/agent-ads-sdk/issues)
|
|
808
504
|
- **Email:** support@attentionmarket.ai
|
|
809
505
|
|
|
810
|
-
---
|
|
811
|
-
|
|
812
506
|
## License
|
|
813
507
|
|
|
814
|
-
MIT
|
|
508
|
+
MIT License. See [LICENSE](LICENSE) for details.
|