@the_ro_show/agent-ads-sdk 0.13.1 → 0.13.3
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 +300 -605
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,450 +1,243 @@
|
|
|
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 defaults to production Supabase endpoint
|
|
99
|
+
// Only override if self-hosting or using different environment
|
|
100
|
+
timeoutMs: 4000, // Optional: request timeout in milliseconds
|
|
101
|
+
maxRetries: 2 // Optional: automatic retry count
|
|
102
|
+
});
|
|
103
|
+
```
|
|
228
104
|
|
|
229
|
-
|
|
105
|
+
## Core Concepts
|
|
230
106
|
|
|
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
|
-
```
|
|
107
|
+
### Placements
|
|
238
108
|
|
|
239
|
-
|
|
109
|
+
A placement defines where ads appear in your application:
|
|
240
110
|
|
|
241
|
-
|
|
111
|
+
- `sponsored_suggestion` — Conversational ad in chat flow (most common)
|
|
112
|
+
- `sponsored_block` — Dedicated ad section in UI
|
|
113
|
+
- `sponsored_tool` — AI agent service recommendation
|
|
242
114
|
|
|
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
|
-
```
|
|
115
|
+
### Ad Response Format
|
|
253
116
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
117
|
+
```typescript
|
|
118
|
+
interface AdResponse {
|
|
119
|
+
request_id: string;
|
|
120
|
+
decision_id: string;
|
|
121
|
+
advertiser_id: string;
|
|
122
|
+
ad_type: 'link' | 'recommendation' | 'service';
|
|
123
|
+
payout: number; // Amount earned on conversion (in cents)
|
|
124
|
+
|
|
125
|
+
creative: {
|
|
126
|
+
title: string;
|
|
127
|
+
body: string;
|
|
128
|
+
cta: string;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
click_url: string; // Tracked click URL (use this)
|
|
132
|
+
tracking_url?: string; // Server-side tracking URL
|
|
133
|
+
tracking_token: string; // For manual event tracking
|
|
134
|
+
|
|
135
|
+
disclosure: {
|
|
136
|
+
label: string;
|
|
137
|
+
explanation: string;
|
|
138
|
+
sponsor_name: string;
|
|
139
|
+
};
|
|
268
140
|
}
|
|
269
141
|
```
|
|
270
142
|
|
|
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.
|
|
143
|
+
### Impression Tracking
|
|
288
144
|
|
|
289
|
-
|
|
145
|
+
**Important:** As of v0.9.0, impression tracking is required to earn revenue from clicks.
|
|
290
146
|
|
|
291
|
-
|
|
147
|
+
The SDK automatically tracks impressions when using `decideFromContext()`. Clicks without prior impressions will redirect users but will not generate revenue.
|
|
292
148
|
|
|
293
|
-
|
|
149
|
+
If using the raw `decide()` API, you must manually track impressions:
|
|
294
150
|
|
|
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)
|
|
151
|
+
```typescript
|
|
152
|
+
await client.trackImpression({
|
|
153
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
154
|
+
request_id: ad.request_id,
|
|
155
|
+
decision_id: ad.decision_id,
|
|
156
|
+
unit_id: ad._ad.unit_id,
|
|
157
|
+
tracking_token: ad.tracking_token
|
|
158
|
+
});
|
|
159
|
+
```
|
|
310
160
|
|
|
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
|
|
161
|
+
## Developer Controls
|
|
315
162
|
|
|
316
|
-
|
|
163
|
+
AttentionMarket provides fine-grained controls over ad selection, quality, and revenue optimization.
|
|
317
164
|
|
|
318
|
-
|
|
165
|
+
### Quality and Brand Safety
|
|
319
166
|
|
|
320
|
-
|
|
167
|
+
#### Minimum Quality Score
|
|
321
168
|
|
|
322
|
-
|
|
169
|
+
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
170
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- ❌ Wrong positive prediction → **-5% penalty**
|
|
331
|
-
- 🤷 Neutral/negative → no bonus/penalty (data only)
|
|
171
|
+
```typescript
|
|
172
|
+
const ad = await client.decideFromContext({
|
|
173
|
+
userMessage: "I need legal help",
|
|
174
|
+
minQualityScore: 0.7 // Only show ads with quality >= 0.7
|
|
175
|
+
});
|
|
176
|
+
```
|
|
332
177
|
|
|
333
|
-
|
|
178
|
+
**Validation:** Must be a number between 0.0 and 1.0.
|
|
334
179
|
|
|
335
|
-
**
|
|
336
|
-
-
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
- Harder to game (can't spam "positive" on everything)
|
|
180
|
+
**Use cases:**
|
|
181
|
+
- Premium applications: `0.8+` for high-quality experiences only
|
|
182
|
+
- Brand-sensitive contexts: `0.7+` to avoid low-quality advertisers
|
|
183
|
+
- General applications: `0.5+` for balanced quality and fill rate
|
|
340
184
|
|
|
341
|
-
|
|
185
|
+
#### Category Filtering
|
|
342
186
|
|
|
343
|
-
|
|
187
|
+
Control which advertiser categories can appear using the IAB Content Taxonomy 3.0 (704 categories across 38 top-level verticals).
|
|
344
188
|
|
|
345
|
-
|
|
346
|
-
- Spamming fake positive responses = net loss
|
|
347
|
-
- Accuracy = net gain (bonus > penalty when right)
|
|
348
|
-
- System rewards honest data collection
|
|
189
|
+
##### Allowed Categories
|
|
349
190
|
|
|
350
|
-
|
|
191
|
+
Whitelist specific categories. Only ads from these categories will be shown.
|
|
351
192
|
|
|
352
193
|
```typescript
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
194
|
+
// Insurance comparison app: only show insurance ads
|
|
195
|
+
const ad = await client.decideFromContext({
|
|
196
|
+
userMessage: "I need car insurance",
|
|
197
|
+
allowedCategories: [31] // 31 = Auto Insurance (IAB category)
|
|
357
198
|
});
|
|
358
199
|
|
|
359
|
-
//
|
|
200
|
+
// Wedding planner: allow wedding + photography + food
|
|
360
201
|
const ad = await client.decideFromContext({
|
|
361
|
-
userMessage: "
|
|
202
|
+
userMessage: "Help me plan my wedding",
|
|
203
|
+
allowedCategories: [
|
|
204
|
+
603, // Weddings
|
|
205
|
+
162, // Photography
|
|
206
|
+
190 // Restaurants
|
|
207
|
+
]
|
|
362
208
|
});
|
|
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
209
|
```
|
|
404
210
|
|
|
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
|
|
211
|
+
##### Blocked Categories
|
|
412
212
|
|
|
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:
|
|
213
|
+
Blacklist specific categories. Ads from these categories will never be shown.
|
|
428
214
|
|
|
429
215
|
```typescript
|
|
216
|
+
// Block all sensitive content (gambling, adult, controversial)
|
|
430
217
|
const ad = await client.decideFromContext({
|
|
431
|
-
userMessage: "
|
|
432
|
-
|
|
218
|
+
userMessage: "Help me with something",
|
|
219
|
+
blockedCategories: [601] // Blocks "Sensitive Topics" + all children
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Legal assistant: block competitor law firms
|
|
223
|
+
const ad = await client.decideFromContext({
|
|
224
|
+
userMessage: "I need legal help",
|
|
225
|
+
blockedCategories: [318] // Block "Legal Services"
|
|
433
226
|
});
|
|
434
227
|
```
|
|
435
228
|
|
|
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
|
|
229
|
+
**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
230
|
|
|
441
|
-
|
|
231
|
+
**Precedence:** If `allowedCategories` is set, `blockedCategories` is ignored.
|
|
442
232
|
|
|
443
|
-
|
|
233
|
+
**Validation rules:**
|
|
234
|
+
- `allowedCategories`: Must be a non-empty array of numbers or strings
|
|
235
|
+
- `blockedCategories`: Must be an array of numbers or strings
|
|
236
|
+
- Empty `allowedCategories: []` is rejected (would block all ads)
|
|
444
237
|
|
|
445
|
-
**
|
|
238
|
+
**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
239
|
|
|
447
|
-
|
|
240
|
+
##### Discovering Categories
|
|
448
241
|
|
|
449
242
|
```typescript
|
|
450
243
|
// Get all 38 top-level categories
|
|
@@ -466,55 +259,9 @@ insurance.categories.forEach(cat => {
|
|
|
466
259
|
// Output: "Automotive > Auto Insurance", "Personal Finance > Insurance", etc.
|
|
467
260
|
```
|
|
468
261
|
|
|
469
|
-
####
|
|
262
|
+
#### Advertiser Blocklist
|
|
470
263
|
|
|
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:
|
|
264
|
+
Block specific advertisers by ID (e.g., based on user feedback or competitive conflicts).
|
|
518
265
|
|
|
519
266
|
```typescript
|
|
520
267
|
const ad = await client.decideFromContext({
|
|
@@ -523,292 +270,240 @@ const ad = await client.decideFromContext({
|
|
|
523
270
|
});
|
|
524
271
|
```
|
|
525
272
|
|
|
526
|
-
|
|
273
|
+
**Validation:** Must be an array of non-empty strings (advertiser IDs).
|
|
527
274
|
|
|
528
|
-
|
|
275
|
+
Advertiser IDs are included in ad responses as `advertiser_id`.
|
|
529
276
|
|
|
530
|
-
|
|
277
|
+
### Revenue Optimization
|
|
531
278
|
|
|
532
|
-
|
|
279
|
+
#### Minimum CPC Filter
|
|
533
280
|
|
|
534
|
-
Only show ads above a
|
|
281
|
+
Only show ads with bids at or above a specified cost-per-click threshold (in cents).
|
|
535
282
|
|
|
536
283
|
```typescript
|
|
537
284
|
const ad = await client.decideFromContext({
|
|
538
285
|
userMessage: "I need car insurance",
|
|
539
|
-
minCPC: 100 // Only ads bidding
|
|
286
|
+
minCPC: 100 // Only ads bidding >= $1.00 per click
|
|
540
287
|
});
|
|
541
288
|
```
|
|
542
289
|
|
|
290
|
+
**Validation:** Must be a non-negative number.
|
|
291
|
+
|
|
543
292
|
**Use cases:**
|
|
544
|
-
-
|
|
545
|
-
-
|
|
546
|
-
-
|
|
293
|
+
- Premium applications: `200+` for $2+ ads only
|
|
294
|
+
- High-value verticals: Filter out low-budget advertisers
|
|
295
|
+
- Revenue targets: Ensure minimum revenue per impression
|
|
296
|
+
- Lower fill rate tolerance: When you'd rather show nothing than a low-value ad
|
|
297
|
+
|
|
298
|
+
**Trade-off:** Higher thresholds = higher revenue per ad but lower fill rate.
|
|
547
299
|
|
|
548
|
-
|
|
300
|
+
#### Minimum Relevance Score
|
|
549
301
|
|
|
550
|
-
Only show ads
|
|
302
|
+
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
303
|
|
|
552
304
|
```typescript
|
|
553
305
|
const ad = await client.decideFromContext({
|
|
554
306
|
userMessage: "Help me plan my wedding",
|
|
555
|
-
minRelevanceScore: 0.8 // Only highly relevant ads
|
|
307
|
+
minRelevanceScore: 0.8 // Only highly relevant ads
|
|
556
308
|
});
|
|
557
309
|
```
|
|
558
310
|
|
|
311
|
+
**Validation:** Must be a number between 0.0 and 1.0.
|
|
312
|
+
|
|
559
313
|
**Use cases:**
|
|
560
|
-
-
|
|
561
|
-
-
|
|
562
|
-
-
|
|
563
|
-
-
|
|
314
|
+
- Niche applications: `0.8+` for specialized content only (e.g., legal assistant)
|
|
315
|
+
- User experience priority: Filter out loosely related ads
|
|
316
|
+
- Context-sensitive placements: Ensure ads match conversation topic
|
|
317
|
+
- Brand-aligned content: Maintain thematic consistency
|
|
318
|
+
|
|
319
|
+
**Important:** This filter only applies to campaigns with semantic targeting. Keyword and automatic campaigns are not affected.
|
|
564
320
|
|
|
565
|
-
|
|
321
|
+
**Default threshold:** Backend applies a minimum threshold of 0.25 for all semantic campaigns (ads below this are never shown).
|
|
566
322
|
|
|
567
|
-
|
|
323
|
+
#### Ranking Strategy
|
|
324
|
+
|
|
325
|
+
Choose how ads are ranked when multiple ads match the request.
|
|
568
326
|
|
|
569
327
|
```typescript
|
|
570
|
-
//
|
|
328
|
+
// Revenue-optimized (default): highest bid wins
|
|
571
329
|
const ad = await client.decideFromContext({
|
|
572
330
|
userMessage: "I need legal help",
|
|
573
331
|
optimizeFor: 'revenue' // Rank by bid × quality × relevance
|
|
574
332
|
});
|
|
575
333
|
|
|
576
|
-
//
|
|
334
|
+
// Relevance-optimized: best match wins
|
|
577
335
|
const ad = await client.decideFromContext({
|
|
578
336
|
userMessage: "I need legal help",
|
|
579
337
|
optimizeFor: 'relevance' // Rank by semantic similarity only
|
|
580
338
|
});
|
|
581
339
|
```
|
|
582
340
|
|
|
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
|
|
341
|
+
**Validation:** Must be either `'revenue'` or `'relevance'`.
|
|
587
342
|
|
|
588
343
|
**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
344
|
|
|
594
|
-
**
|
|
595
|
-
-
|
|
596
|
-
-
|
|
597
|
-
-
|
|
345
|
+
- **Revenue mode:** Winner is ranked by composite score (bid × quality × relevance), pays just enough to beat the next ad's composite score + $0.01
|
|
346
|
+
- **Relevance mode:** Winner is ranked by semantic similarity, pays just enough to beat the next ad in composite score space + $0.01
|
|
347
|
+
- **Price cap:** Winner never pays more than their max bid (auction integrity guaranteed)
|
|
348
|
+
- **Price floor:** Minimum clearing price of $0.25 ensures platform sustainability
|
|
349
|
+
|
|
350
|
+
**Use cases:**
|
|
351
|
+
- General applications: `'revenue'` to maximize earnings
|
|
352
|
+
- Niche applications: `'relevance'` to prioritize perfect matches over high bids
|
|
353
|
+
- Premium experiences: Combine with high `minRelevanceScore` + `'relevance'` ranking
|
|
354
|
+
|
|
355
|
+
#### Combined Controls
|
|
598
356
|
|
|
599
|
-
|
|
357
|
+
Combine multiple controls for precise ad selection:
|
|
600
358
|
|
|
601
359
|
```typescript
|
|
602
|
-
// Premium legal assistant:
|
|
360
|
+
// Premium legal assistant: high relevance + high bids + category filter
|
|
603
361
|
const ad = await client.decideFromContext({
|
|
604
362
|
userMessage: "I need estate planning help",
|
|
605
|
-
minRelevanceScore: 0.8,
|
|
606
|
-
minCPC: 200,
|
|
607
|
-
|
|
608
|
-
|
|
363
|
+
minRelevanceScore: 0.8, // Only highly relevant
|
|
364
|
+
minCPC: 200, // Only $2+ bids
|
|
365
|
+
minQualityScore: 0.7, // Only high-quality advertisers
|
|
366
|
+
optimizeFor: 'relevance', // Best match wins
|
|
367
|
+
allowedCategories: [318] // Legal services only
|
|
609
368
|
});
|
|
369
|
+
```
|
|
610
370
|
|
|
611
|
-
|
|
371
|
+
## Advanced Features
|
|
372
|
+
|
|
373
|
+
### Multi-Turn Conversations
|
|
374
|
+
|
|
375
|
+
Include conversation history for better ad matching:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
612
378
|
const ad = await client.decideFromContext({
|
|
613
|
-
userMessage: "
|
|
614
|
-
|
|
615
|
-
|
|
379
|
+
userMessage: "What are my options?",
|
|
380
|
+
conversationHistory: [
|
|
381
|
+
"User: My car insurance is too expensive",
|
|
382
|
+
"Agent: I can help you compare rates",
|
|
383
|
+
"User: What are my options?"
|
|
384
|
+
]
|
|
616
385
|
});
|
|
617
386
|
```
|
|
618
387
|
|
|
619
|
-
|
|
388
|
+
The SDK automatically limits history to the last 5 messages to prevent token overflow.
|
|
620
389
|
|
|
621
|
-
|
|
390
|
+
### Geographic and Platform Targeting
|
|
622
391
|
|
|
623
392
|
```typescript
|
|
624
393
|
const ad = await client.decideFromContext({
|
|
625
394
|
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
|
|
395
|
+
country: 'US',
|
|
396
|
+
language: 'en',
|
|
397
|
+
platform: 'ios' // 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other'
|
|
633
398
|
});
|
|
634
399
|
```
|
|
635
400
|
|
|
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`
|
|
401
|
+
### Click Tracking
|
|
675
402
|
|
|
676
|
-
|
|
403
|
+
Clicks are automatically tracked when users visit `click_url`. For manual tracking:
|
|
677
404
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
405
|
+
```typescript
|
|
406
|
+
await client.trackClick({
|
|
407
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
408
|
+
request_id: ad.request_id,
|
|
409
|
+
decision_id: ad.decision_id,
|
|
410
|
+
unit_id: ad._ad.unit_id,
|
|
411
|
+
tracking_token: ad.tracking_token,
|
|
412
|
+
href: ad.click_url,
|
|
413
|
+
click_context: "User clicked 'Get a Quote' button"
|
|
414
|
+
});
|
|
684
415
|
```
|
|
685
416
|
|
|
686
|
-
|
|
417
|
+
Simplified tracking from ad object:
|
|
687
418
|
|
|
688
|
-
```
|
|
689
|
-
{
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
"language": "en",
|
|
693
|
-
"platform": "ios"
|
|
694
|
-
}
|
|
419
|
+
```typescript
|
|
420
|
+
await client.trackClickFromAd(ad, {
|
|
421
|
+
click_context: "User clicked on sponsored suggestion"
|
|
422
|
+
});
|
|
695
423
|
```
|
|
696
424
|
|
|
697
|
-
###
|
|
425
|
+
### Conversion Tracking
|
|
698
426
|
|
|
699
|
-
|
|
700
|
-
{
|
|
701
|
-
"context": "User needs a wedding photographer in Austin",
|
|
702
|
-
"response_type": "agent"
|
|
703
|
-
}
|
|
704
|
-
```
|
|
427
|
+
Track conversions (purchases, signups, etc.) to improve advertiser ROI and your quality score:
|
|
705
428
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
429
|
+
```typescript
|
|
430
|
+
await client.track({
|
|
431
|
+
event_id: `evt_${generateUUID()}`,
|
|
432
|
+
event_type: 'conversion',
|
|
433
|
+
occurred_at: new Date().toISOString(),
|
|
434
|
+
agent_id: 'agt_YOUR_AGENT_ID',
|
|
435
|
+
request_id: ad.request_id,
|
|
436
|
+
decision_id: ad.decision_id,
|
|
437
|
+
unit_id: ad._ad.unit_id,
|
|
438
|
+
tracking_token: ad.tracking_token,
|
|
439
|
+
metadata: {
|
|
440
|
+
conversion_value: 99.99,
|
|
441
|
+
conversion_type: 'purchase'
|
|
442
|
+
}
|
|
443
|
+
});
|
|
719
444
|
```
|
|
720
445
|
|
|
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
|
-
```
|
|
446
|
+
## Error Handling
|
|
746
447
|
|
|
747
|
-
|
|
448
|
+
The SDK throws errors for invalid configurations and failed requests:
|
|
748
449
|
|
|
749
|
-
```
|
|
750
|
-
{
|
|
751
|
-
|
|
752
|
-
|
|
450
|
+
```typescript
|
|
451
|
+
try {
|
|
452
|
+
const ad = await client.decideFromContext({
|
|
453
|
+
userMessage: "I need car insurance",
|
|
454
|
+
minQualityScore: -0.5 // Invalid: must be 0.0-1.0
|
|
455
|
+
});
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error(error.message);
|
|
458
|
+
// Output: "minQualityScore must be a number between 0.0 and 1.0"
|
|
753
459
|
}
|
|
754
460
|
```
|
|
755
461
|
|
|
756
|
-
###
|
|
462
|
+
### Validation Errors
|
|
757
463
|
|
|
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) |
|
|
464
|
+
The SDK validates all parameters before making API calls. Common validation errors:
|
|
766
465
|
|
|
767
|
-
|
|
466
|
+
- `minQualityScore must be a number between 0.0 and 1.0`
|
|
467
|
+
- `minCPC must be a non-negative number (cost-per-click in cents)`
|
|
468
|
+
- `minRelevanceScore must be a number between 0.0 and 1.0`
|
|
469
|
+
- `optimizeFor must be either "revenue" or "relevance"`
|
|
470
|
+
- `allowedCategories cannot be empty (would block all ads). Use blockedCategories to exclude specific categories, or omit to allow all.`
|
|
471
|
+
- `blockedAdvertisers must contain non-empty strings (advertiser IDs)`
|
|
768
472
|
|
|
769
|
-
### HTTP
|
|
473
|
+
### HTTP Errors
|
|
770
474
|
|
|
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 |
|
|
475
|
+
The API returns standard HTTP status codes:
|
|
778
476
|
|
|
779
|
-
|
|
477
|
+
- `400 Bad Request` — Invalid parameters (see error message for details)
|
|
478
|
+
- `401 Unauthorized` — Missing or invalid API key
|
|
479
|
+
- `429 Too Many Requests` — Rate limit exceeded
|
|
480
|
+
- `500 Internal Server Error` — Server error (contact support if persistent)
|
|
780
481
|
|
|
781
|
-
##
|
|
482
|
+
## Rate Limits
|
|
782
483
|
|
|
783
|
-
|
|
484
|
+
- **Per IP:** 60 requests per minute
|
|
485
|
+
- **Per API key:** 100 requests per minute
|
|
784
486
|
|
|
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)
|
|
487
|
+
Rate limits are enforced to prevent abuse and ensure fair resource allocation. If you need higher limits, contact support.
|
|
792
488
|
|
|
793
|
-
|
|
489
|
+
## Testing
|
|
794
490
|
|
|
795
|
-
|
|
491
|
+
Use test API keys (`am_test_...`) for development and testing. Test keys:
|
|
796
492
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
493
|
+
- Return test ads with realistic data
|
|
494
|
+
- Do not charge advertisers
|
|
495
|
+
- Do not generate real revenue
|
|
496
|
+
- Have the same rate limits as live keys
|
|
801
497
|
|
|
802
|
-
|
|
498
|
+
Switch to live keys (`am_live_...`) when deploying to production.
|
|
803
499
|
|
|
804
500
|
## Support
|
|
805
501
|
|
|
806
|
-
- **
|
|
807
|
-
- **
|
|
502
|
+
- **Documentation:** [docs.attentionmarket.ai](https://docs.attentionmarket.ai)
|
|
503
|
+
- **API Reference:** [api.attentionmarket.ai/docs](https://api.attentionmarket.ai/docs)
|
|
504
|
+
- **Issues:** [github.com/rtrivedi/agent-ads-sdk/issues](https://github.com/rtrivedi/agent-ads-sdk/issues)
|
|
808
505
|
- **Email:** support@attentionmarket.ai
|
|
809
506
|
|
|
810
|
-
---
|
|
811
|
-
|
|
812
507
|
## License
|
|
813
508
|
|
|
814
|
-
MIT
|
|
509
|
+
MIT License. See [LICENSE](LICENSE) for details.
|