Skip to main content

API Reference

All endpoints are served from https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1.

The SDK handles auth headers automatically. For raw HTTP calls, include:

  • Authorization: Bearer <supabase_anon_key> — See Mobile SDKs for the anon key value
  • X-AM-API-Key: <your_api_key> — Your developer API key from signup

SDK Configuration

const client = new PenguinClient({
apiKey: 'am_test_...', // Required. Your API key.
baseUrl: '...', // Optional. Override the API base URL.
supabaseAnonKey: '...', // Optional. Override the Supabase anon key.
timeoutMs: 10_000, // Optional. Request timeout (default: 10s).
maxRetries: 2, // Optional. Retries for GET requests (default: 2).
debug: false, // Optional. Enable debug logging (default: false).
});

:::info Retry behavior GET requests are automatically retried on 408, 429, and 5xx errors with exponential backoff. POST requests are not retried by default to prevent duplicate side effects. Event tracking (trackEvent) is an exception — it is idempotent and retried automatically. :::


POST /decide

Get contextual ads matched to user intent. This is the primary endpoint.

SDK

const response = await client.decideFromContext({
context: 'I need a tax accountant',
max_results: 3,
min_quality_score: 0.5,
});

Parameters

FieldTypeRequiredDescription
contextstringYesThe user's message or query
user_intentstringNoAdditional intent context
categoriesstring[]NoIAB categories to target
blocked_categoriesstring[]NoIAB categories to exclude
blocked_advertisersstring[]NoAdvertiser IDs to exclude
min_quality_scorenumberNoMinimum quality score (0-1)
min_relevance_scorenumberNoMinimum relevance score (0-1)
max_resultsnumberNoMax ads to return (default: 5)
response_formatstringNoconcise or verbose
max_wait_msnumberNoMaximum auction wait time
placement_idstringNoIdentifier for ad placement location

Response

{
"status": "fill",
"request_id": "req_abc123",
"decision_id": "dec_xyz",
"units": [
{
"creative": {
"title": "CloudTax — AI Tax Filing",
"body": "File your freelancer taxes in 15 minutes with AI guidance",
"cta": "Start Free",
"landing_url": "https://cloudtax.ca"
},
"click_url": "https://...supabase.co/functions/v1/track-click/eyJ...",
"tracking_token": "trk_abc...",
"_score": {
"relevance": 0.92,
"quality": 0.85,
"bid": 0.50,
"final": 0.39
},
"_meta": {
"unit_id": "uuid-here",
"campaign_id": "uuid-here",
"clearing_price_cents": 35,
"position": 1
}
}
]
}

cURL

curl -X POST https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/decide \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SUPABASE_ANON_KEY" \
-H "X-AM-API-Key: $AM_API_KEY" \
-d '{"context": "I need a tax accountant"}'

POST /event

Track ad events (impressions, clicks, conversions).

tip

decideFromContext() automatically tracks impressions. You only need this for manual tracking or custom events.

SDK

await client.trackEvent({
event_id: 'evt_unique_id',
occurred_at: new Date().toISOString(),
agent_id: 'agt_your_id',
unit_id: 'ad-unit-uuid',
event_type: 'impression',
tracking_token: 'trk_...',
});

Parameters

FieldTypeRequiredDescription
event_idstringYesUnique event identifier
occurred_atstringYesISO 8601 timestamp
agent_idstringYesYour agent ID
unit_idstringYesAd unit ID from response
event_typestringYesimpression, click, conversion, ad_shown, ad_dismissed, agent_call
tracking_tokenstringNoTracking token from ad
metadataobjectNoAdditional event data

Response

{ "accepted": true }

POST /feedback

Submit developer predictions about ad relevance for bonus payouts.

SDK

// Manual prediction
await client.sendFeedback({
tracking_token: ad.tracking_token,
reaction: 'positive',
});

// Auto-analysis from user's response text
await client.sendFeedback({
tracking_token: ad.tracking_token,
user_response: "That's exactly what I was looking for!",
conversation_history: ['I need a tax tool', 'Here is CloudTax...'],
});

Parameters

FieldTypeRequiredDescription
tracking_tokenstringYesToken from the ad response
reactionstringNo*positive, neutral, or negative
user_responsestringNo*User's response text for auto-analysis
conversation_historystring[]NoRecent messages for context
contextstringNoAdditional context (max 1000 chars)
idempotency_keystringNoPrevent duplicate submissions

*One of reaction or user_response is required.

Response

{
"status": "received",
"feedback_id": "evt_abc123",
"resolution_date": "2026-04-20",
"potential_bonus": "20%",
"message": "Feedback recorded. Bonus will be calculated after 7-day conversion window."
}

POST /service-result

Report the outcome of an agent-to-agent service transaction.

SDK

await client.logServiceResult({
transaction_id: 'txn_abc123',
success: true,
metadata: { items_processed: 5 },
});

Parameters

FieldTypeRequiredDescription
transaction_idstringYesTransaction ID
successbooleanYesWhether the service completed successfully
metadataobjectNoAdditional result data

Response

{
"transaction_id": "txn_abc123",
"success": true,
"payment_triggered": true,
"payment_amount": 0.35,
"message": "Service completed successfully. Payment triggered."
}

POST /rate-business

Rate a business interaction quality. Requires a verified click first.

SDK

await client.rateBusiness({
tracking_token: ad.tracking_token,
ad_unit_id: ad._meta!.unit_id,
rating: 4,
context: 'Fast response, helpful information',
});

Parameters

FieldTypeRequiredDescription
tracking_tokenstringYesToken from the ad response
ad_unit_idstringYesAd unit ID
ratingnumberYes1-5 rating
contextstringNoOptional review text (max 500 chars)

POST /agent-signup

Register a new developer/agent. No API key needed.

SDK

const agent = await PenguinClient.signup({
owner_email: 'dev@example.com',
agent_name: 'MyBot',
});

Parameters

FieldTypeRequiredDescription
owner_emailstringYesDeveloper email
agent_namestringYesAgent name (1-100 chars)
sdk_typestringNoSDK identifier
declared_placementsstring[]NoWhere ads will appear

REST API (api-v1)

A simplified REST API that mirrors the core functionality. Useful for non-TypeScript integrations.

EndpointDescription
GET /api-v1/openapi.jsonOpenAPI 3.1.0 spec
POST /api-v1/searchSearch for capabilities
POST /api-v1/session/startStart interactive session
POST /api-v1/session/messageContinue session
POST /api-v1/session/endEnd session
POST /api-v1/feedbackSubmit feedback

Search example (Python)

import requests

ANON_KEY = 'eyJhbGciOiJIUzI1NiIs...' # See Mobile SDKs page for full key
API_KEY = 'am_live_your_key'

response = requests.post(
'https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/api-v1/search',
headers={
'Authorization': f'Bearer {ANON_KEY}',
'X-AM-API-Key': API_KEY,
},
json={'query': 'best CRM for startups', 'max_results': 3},
)
data = response.json()
for cap in data['capabilities']:
print(f"{cap['name']}{cap['description']}")

Error handling

The SDK exports typed error classes for structured error handling:

import {
PenguinClient,
APIRequestError,
NetworkError,
TimeoutError,
ValidationError,
} from 'penguin-sdk';

try {
const response = await client.decideFromContext({ context: userMessage });
} catch (err) {
if (err instanceof ValidationError) {
// Invalid parameters — fix your request
console.error('Bad request:', err.message);
} else if (err instanceof TimeoutError) {
// Server didn't respond in time
console.error('Timeout after', err.timeoutMs, 'ms');
} else if (err instanceof APIRequestError) {
// Server returned an error status
console.error('API error:', err.status, err.code, err.body);
} else if (err instanceof NetworkError) {
// Network failure after retries
console.error('Network error:', err.message);
}
}

Error codes

StatusCodeDescription
400VariousInvalid request parameters
401authentication_failedMissing or invalid API key
403forbiddenResource doesn't belong to your agent
404not_foundResource not found
409duplicate_*Idempotent — already processed
429rate_limitedToo many requests. Check Retry-After header
500internal_errorServer error — safe to retry
503service_unavailableFeature temporarily disabled