Overview
The Agents API provides direct execution of single-purpose agents (also called “Quick Tools”) without LLM orchestration. Each agent wraps a specific tool and returns structured results.
Key Differences from Task API:
Agents API : Direct tool execution, no AI orchestration, asynchronous results
Task API : Multi-step workflows, LLM planning, asynchronous execution
All agent executions are asynchronous (return task_id), even though agents perform single operations. Use the Task Status API to retrieve results.
Base URL
http://localhost:8080/api/v1/agents
Production: https://your-domain.com/api/v1/agents
Authentication
Required : Yes
Include API key in header:
X-API-Key: sk_your_api_key
Development Default : Authentication is disabled when GATEWAY_SKIP_AUTH=1 is set.
Endpoints
List Agents
GET /api/v1/agents
Returns all available agents with their schemas and metadata.
Request
curl http://localhost:8080/api/v1/agents \
-H "X-API-Key: sk_test_123456"
Response
{
"agents" : [
{
"id" : "serp-ads" ,
"name" : "SERP Ads Extract" ,
"description" : "Extract paid ads from Google Search results for given keywords" ,
"category" : "ads_research" ,
"tool" : "ads_serp_extract" ,
"input_schema" : {
"required" : [ "keywords" ],
"properties" : {
"keywords" : {
"type" : "string" ,
"description" : "Search keywords to find ads for"
},
"country" : {
"type" : "string" ,
"default" : "us" ,
"description" : "Country code (us, jp, uk, etc.)"
}
}
},
"cost_per_call" : 0.015
}
],
"count" : 14
}
Response Fields
Field Type Description agentsarray List of agent definitions countinteger Total number of agents
Agent Object:
Field Type Description idstring Agent identifier (used in execute endpoint) namestring Human-readable name descriptionstring What the agent does categorystring Agent category (ads_research, financial, etc.) toolstring Underlying tool name input_schemaobject JSON schema for input validation cost_per_callnumber Estimated cost per execution (USD)
Get Agent Details
GET /api/v1/agents/
Returns details for a specific agent, including its input schema.
Request
curl http://localhost:8080/api/v1/agents/serp-ads \
-H "X-API-Key: sk_test_123456"
Response
{
"id" : "serp-ads" ,
"name" : "SERP Ads Extract" ,
"description" : "Extract paid ads from Google Search results for given keywords" ,
"category" : "ads_research" ,
"tool" : "ads_serp_extract" ,
"input_schema" : {
"required" : [ "keywords" ],
"properties" : {
"keywords" : {
"type" : "string" ,
"description" : "Search keywords to find ads for"
},
"country" : {
"type" : "string" ,
"default" : "us"
},
"device" : {
"type" : "string" ,
"enum" : [ "desktop" , "mobile" , "tablet" ],
"default" : "desktop"
}
}
},
"cost_per_call" : 0.015
}
Error Responses
404 Not Found - Agent does not exist:
{
"error" : "Agent not found: invalid-agent-id"
}
Execute Agent
POST /api/v1/agents/
Executes a specific agent with provided input. Returns a task ID immediately; the agent runs asynchronously.
Header Required Description X-API-KeyYes API authentication key Content-TypeYes Must be application/json
Request Body
Parameter Type Required Description inputobject Yes Agent-specific input parameters (validated against input_schema) session_idstring No Session identifier for tracking (auto-generated if omitted) streamboolean No Enable streaming (reserved for future use)
Example: Execute SERP Ads Agent
curl -X POST http://localhost:8080/api/v1/agents/serp-ads \
-H "X-API-Key: sk_test_123456" \
-H "Content-Type: application/json" \
-d '{
"session_id": "user-session-123",
"input": {
"keywords": "best credit cards",
"country": "us",
"device": "desktop"
}
}'
Response
Status : 202 Accepted
Headers :
X-Workflow-ID: Temporal workflow identifier
X-Session-ID: Session identifier
Body :
{
"task_id" : "task-abc123" ,
"agent_id" : "serp-ads" ,
"status" : "STATUS_CODE_OK" ,
"created_at" : "2026-02-15T10:30:00Z"
}
Retrieve Results
Use the Get Task Status endpoint with the returned task_id:
curl http://localhost:8080/api/v1/tasks/task-abc123 \
-H "X-API-Key: sk_test_123456"
Response when completed:
{
"task_id" : "task-abc123" ,
"status" : "TASK_STATUS_COMPLETED" ,
"result" : "{ \" keywords \" : \" best credit cards \" , \" total_ads \" :5, \" ads \" :[...]}" ,
"response" : {
"keywords" : "best credit cards" ,
"total_ads" : 5 ,
"ads" : [
{
"position" : 1 ,
"title" : "Best Credit Cards 2026" ,
"description" : "Compare top credit cards..." ,
"link" : "https://example.com/cards" ,
"domain" : "example.com"
}
],
"cost_usd" : 0.015 ,
"timestamp" : "2026-02-15T10:30:00Z"
},
"model_used" : "claude-sonnet-4-20250514" ,
"provider" : "anthropic" ,
"usage" : {
"total_tokens" : 1250 ,
"input_tokens" : 800 ,
"output_tokens" : 450 ,
"estimated_cost" : 0.018
}
}
Error Responses
400 Bad Request - Invalid input:
{
"error" : "input validation failed: missing required field: keywords"
}
404 Not Found - Agent does not exist:
{
"error" : "Agent not found: invalid-agent"
}
429 Too Many Requests - Rate limit exceeded:
{
"error" : "Rate limit exceeded"
}
All agent inputs are validated against the agent’s input_schema before execution.
Validation Rules:
Required fields must be present and non-null
Type checking - strings, integers, booleans, arrays, objects
Enum validation - values must be in allowed list
Unknown fields - rejected for security (not in schema)
Example Schema:
{
"required" : [ "keywords" ],
"properties" : {
"keywords" : {
"type" : "string" ,
"description" : "Search keywords"
},
"device" : {
"type" : "string" ,
"enum" : [ "desktop" , "mobile" , "tablet" ],
"default" : "desktop"
},
"max_results" : {
"type" : "integer" ,
"default" : 10
}
}
}
Valid input:
{
"keywords" : "best shoes" ,
"device" : "mobile" ,
"max_results" : 5
}
Invalid input (missing required field):
Error: "input validation failed: missing required field: keywords"
Invalid input (unknown field):
{
"keywords" : "shoes" ,
"unknown_field" : "value"
}
Error: "input validation failed: unknown field: unknown_field (not defined in agent schema)"
Available Agents
Shannon provides 14+ specialized agents across multiple categories.
For a complete catalog of available agents with detailed schemas and examples, see:
Ads Research Agents 10 agents for competitive advertising analysis
Financial Research Agents 4 agents for stock news and sentiment analysis
Quick Reference by Category
Ads Research (10 agents):
serp-ads - Extract Google paid ads
yahoo-jp-ads - Extract Yahoo Japan sponsored ads
meta-ad-library - Search Meta Ad Library (Facebook/Instagram)
competitor-discover - Find competitor advertisers
ads-transparency - Multi-platform ad transparency data
lp-visual-analyze - Screenshot and analyze landing pages
lp-batch-analyze - Batch analyze multiple landing pages
ad-creative-analyze - Analyze ad copy patterns
keyword-extract - Extract search keywords from text
browser-screenshot - Capture webpage screenshots
Financial Tools (4 agents):
sec-filings - SEC EDGAR filings lookup
twitter-sentiment - X/Twitter sentiment via xAI
alpaca-news - Stock news from Alpaca Markets
news-aggregator - Multi-source news aggregation
Unified Task API Alternative
You can also execute agents through the unified Task API using the context.agent parameter:
curl -X POST http://localhost:8080/api/v1/tasks \
-H "X-API-Key: sk_test_123456" \
-H "Content-Type: application/json" \
-d '{
"query": "NVDA",
"session_id": "user-session-123",
"context": {
"agent": "sec-filings",
"agent_input": {
"ticker": "NVDA",
"days_back": 90
}
}
}'
Both approaches are equivalent :
Dedicated endpoint: POST /api/v1/agents/{id}
Unified endpoint: POST /api/v1/tasks with context.agent
Best Practices
Use the GET endpoint to retrieve the agent’s schema, then validate your input client-side:
import httpx
# Get schema
agent = httpx.get(
"http://localhost:8080/api/v1/agents/serp-ads" ,
headers ={ "X-API-Key" : "sk_test_123456" }
).json()
# Validate required fields
required = agent[ "input_schema" ][ "required" ]
input_data = { "keywords" : "shoes" , "device" : "mobile" }
for field in required:
if field not in input_data:
raise ValueError ( f "Missing required field: { field } " )
2. Handle Async Results
All agents return task IDs immediately. Poll for results:
import time
# Execute agent
response = httpx.post(
"http://localhost:8080/api/v1/agents/serp-ads" ,
headers ={ "X-API-Key" : "sk_test_123456" },
json ={ "input" : { "keywords" : "shoes" }}
).json()
task_id = response[ "task_id" ]
# Poll for completion
while True :
status = httpx.get(
f "http://localhost:8080/api/v1/tasks/ { task_id } " ,
headers ={ "X-API-Key" : "sk_test_123456" }
).json()
if status[ "status" ] == "TASK_STATUS_COMPLETED" :
print (status[ "response" ])
break
time.sleep( 2 )
3. Use Sessions for Context
Reuse session_id across related agent calls:
session_id = "user-123-analysis"
# First agent call
httpx.post(..., json ={
"session_id" : session_id,
"input" : { "keywords" : "shoes" }
})
# Second agent call (same session)
httpx.post(..., json ={
"session_id" : session_id,
"input" : { "urls" : [ "https://example.com" ]}
})
4. Check Cost Estimates
Before executing expensive agents, check cost_per_call:
agent = httpx.get(
"http://localhost:8080/api/v1/agents/twitter-sentiment" ,
headers ={ "X-API-Key" : "sk_test_123456" }
).json()
if agent[ "cost_per_call" ] > 0.10 :
print ( f "Warning: High cost agent ($ { agent[ 'cost_per_call' ] } )" )
Code Examples
Python with httpx
import httpx
# List all agents
agents = httpx.get(
"http://localhost:8080/api/v1/agents" ,
headers ={ "X-API-Key" : "sk_test_123456" }
).json()
print ( f "Found { agents[ 'count' ] } agents" )
# Execute specific agent
response = httpx.post(
"http://localhost:8080/api/v1/agents/serp-ads" ,
headers ={
"X-API-Key" : "sk_test_123456" ,
"Content-Type" : "application/json"
},
json ={
"session_id" : "my-session" ,
"input" : {
"keywords" : "running shoes" ,
"country" : "us" ,
"device" : "mobile"
}
}
).json()
print ( f "Task ID: { response[ 'task_id' ] } " )
JavaScript/Node.js
const axios = require ( 'axios' );
// Get agent details
const agent = await axios . get (
'http://localhost:8080/api/v1/agents/serp-ads' ,
{
headers: { 'X-API-Key' : 'sk_test_123456' }
}
);
console . log ( 'Agent schema:' , agent . data . input_schema );
// Execute agent
const response = await axios . post (
'http://localhost:8080/api/v1/agents/serp-ads' ,
{
session_id: 'my-session' ,
input: {
keywords: 'running shoes' ,
country: 'us'
}
},
{
headers: {
'X-API-Key' : 'sk_test_123456' ,
'Content-Type' : 'application/json'
}
}
);
console . log ( 'Task ID:' , response . data . task_id );
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type AgentExecuteRequest struct {
SessionID string `json:"session_id,omitempty"`
Input map [ string ] interface {} `json:"input"`
}
func executeAgent ( agentID string , input map [ string ] interface {}) ( string , error ) {
req := AgentExecuteRequest {
SessionID : "my-session" ,
Input : input ,
}
body , _ := json . Marshal ( req )
httpReq , _ := http . NewRequest (
"POST" ,
fmt . Sprintf ( "http://localhost:8080/api/v1/agents/ %s " , agentID ),
bytes . NewBuffer ( body ),
)
httpReq . Header . Set ( "X-API-Key" , "sk_test_123456" )
httpReq . Header . Set ( "Content-Type" , "application/json" )
client := & http . Client {}
resp , err := client . Do ( httpReq )
if err != nil {
return "" , err
}
defer resp . Body . Close ()
var result map [ string ] interface {}
json . NewDecoder ( resp . Body ). Decode (& result )
return result [ "task_id" ].( string ), nil
}
func main () {
taskID , _ := executeAgent ( "serp-ads" , map [ string ] interface {}{
"keywords" : "running shoes" ,
"country" : "us" ,
})
fmt . Printf ( "Task ID: %s \n " , taskID )
}
Submit Task Unified task submission with AI orchestration
Get Task Status Retrieve agent execution results
Ads Research Agents Complete ads research agent catalog
Financial Agents Financial research agent catalog