Search AgentPowers skills API

Site api.agentpowers.aiTask search-agentpowers-skillsVersion v8Updated Sep 16, 2026Category search

Search AgentPowers skills and agents through its JSON API and return exact result fields, response nesting, pagination metadata, normalized records, and alternate raw metadata names. This skill was captured from a live agent session on api.agentpowers.ai and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Search AgentPowers through its JSON search endpoint and return response metadata plus normalized records for skills and agents. Preserve URL-decoded queries, echoed values, pagination fields, source sections, null-normalized metadata, and per-record raw-versus-normalized audits for security, counts, ratings, authors, and sources.

Use Cases

  • Find skills and agents matching a name, keyword, or phrase.
  • Restrict results to skills or agents with the type parameter.
  • Audit alternate nesting and field names for security, usage, ratings, authors, and sources.
  • Retrieve pricing, source metadata, pagination, and response-shape details.
  • Validate the API's 200-character query boundary.

Automation Flow

  1. Build one URL per page as https://api.agentpowers.ai/v1/search?q={URL-encoded-query}&limit={limit}&offset={offset}; omit type for both categories, or append &type={skill|agent} for one category. Encode Unicode with encodeURIComponent.
  2. In one BQL session, goto each URL and run this extractor immediately after navigation. Concatenate records in offset order; stop when the relevant total is reached, a page is empty, or both source totals are zero. For boundary validation, navigate once with exactly 200 query characters and once with 201, recording each status.
(()=>{
const text=document.body?.innerText||document.body?.textContent||'';const p=new URLSearchParams(location.search);let root;
try{root=JSON.parse(text)}catch(e){return {parse_error:String(e),query:p.get('q'),query_length:[...(p.get('q')||'')].length,type:p.get('type')||null,limit:Number(p.get('limit')),offset:Number(p.get('offset')),records:[]}};
const norm=v=>v===undefined||v===null||(typeof v==='string'&&!v.trim())?null:v;
const pick=(o,ks)=>{for(const k of ks)if(o&&o[k]!==undefined&&o[k]!==null)return o[k];return null};
const section=v=>{const s=v&&typeof v==='object'?v:{},items=Array.isArray(s.items)?s.items:[];return {keys:Object.keys(s).sort(),item_keys:items[0]&&typeof items[0]==='object'?Object.keys(items[0]).sort():[],items_present:Array.isArray(s.items),total:s.total??null,limit:s.limit??null,offset:s.offset??null,item_count:items.length}};
const ap=section(root.agentpowers),ch=section(root.clawhub);
const find=(x,out=[],seen=new Set())=>{if(Array.isArray(x)){x.forEach(v=>find(v,out,seen));return out}if(!x||typeof x!=='object')return out;if(typeof x.slug==='string'&&(typeof x.title==='string'||typeof x.name==='string')){const k=x.slug+'\u0000'+String(pick(x,['type','kind']));if(!seen.has(k)){seen.add(k);out.push(x)}}Object.values(x).forEach(v=>{if(v&&typeof v==='object')find(v,out,seen)});return out};
const collect=(o,test,path=[],out=[])=>{if(Array.isArray(o)){o.forEach((v,i)=>collect(v,test,path.concat(i),out));return out}if(!o||typeof o!=='object')return out;for(const[k,v]of Object.entries(o)){const q=path.concat(k);if(test(k))out.push({path:q.join('.'),key:k,value:v});if(v&&typeof v==='object')collect(v,test,q,out)}return out};
const defs={security_status:{keys:['security_status','securityStatus','security','ap_security_status','source_security'],test:k=>/security|status/i.test(k)},install_count:{keys:['install_count','installCount','installs','source_installs'],test:k=>/install/i.test(k)},download_count:{keys:['download_count','downloadCount','downloads','source_downloads'],test:k=>/download/i.test(k)},rating:{keys:['rating','rating_average','average_rating','averageRating','avgRating','source_rating'],test:k=>/rating|review/i.test(k)},author:{keys:['author','creator','owner','owner_display_name','author_name','creator_name'],test:k=>/author|creator|owner/i.test(k)},source:{keys:['source','provider','origin','source_url'],test:k=>/source|provider|origin/i.test(k)}};
const records=find(root).map(o=>{const raw={},normalized={};for(const[n,d]of Object.entries(defs))raw[n]=collect(o,d.test).map(x=>({path:x.path,key:x.key,value:x.value}));const ao=pick(o,['author','creator','owner']);normalized.security_status=norm(pick(o,defs.security_status.keys));normalized.install_count=norm(pick(o,defs.install_count.keys));normalized.download_count=norm(pick(o,defs.download_count.keys));normalized.rating=norm(pick(o,defs.rating.keys));normalized.author=norm(typeof ao==='object'?pick(ao,['name','username','handle','slug','display_name','displayName']):ao)||norm(pick(o,['owner_display_name','author_name','creator_name']));normalized.source=norm(pick(o,defs.source.keys));return {slug:norm(o.slug),title:norm(pick(o,['title','name'])),description:norm(pick(o,['description','summary'])),type:norm(pick(o,['type','kind'])),price_cents:norm(o.price_cents),currency:norm(o.currency),version:norm(o.version),matches_requested_type:norm(pick(o,['type','kind']))===p.get('type'),raw_values:raw,normalized_values:normalized}});
return {query:p.get('q')||'',query_length:[...(p.get('q')||'')].length,echoed_query:norm(root.agentpowers?.query??root.query??null),type:p.get('type'),limit:root.agentpowers?.limit??Number(p.get('limit')),offset:root.agentpowers?.offset??Number(p.get('offset')),total:root.agentpowers?.total??null,shape:{agentpowers:{keys:ap.keys,item_keys:ap.item_keys,items_present:ap.items_present},clawhub:{keys:ch.keys,item_keys:ch.item_keys,items_present:ch.items_present}},sources:{agentpowers:{total:ap.total,limit:ap.limit,offset:ap.offset,item_count:ap.item_count},clawhub:{total:ch.total,limit:ch.limit,offset:ch.offset,item_count:ch.item_count}},raw_record_count:records.length,matching_type_count:p.get('type')?records.filter(x=>x.matches_requested_type).length:records.length,records};
})()
  1. For a zero-result type-filtered search, report agentpowers.items: [], agentpowers.total: 0, requested limit and offset, plus separate clawhub.items and clawhub.total; do not treat ClawHub objects as AgentPowers records.

Params

ParamWhat it doesExample value
queryKeyword or phrase; URL-encode before insertionsecurity audit
typeOptional category restrictionagent
limitMaximum records returned per page100
offsetNumber of records skipped; increment by limit0, then 100
boundary_testOptional validation at the accepted query-length boundary200, 201

Possible Friction Points

TriggerAction
Response JSON has no agentpowers.items array or returns an empty resultReturn an empty AgentPowers record list and preserve totals, pagination, and shape metadata.
Type-filtered search returns zero recordsReport the empty AgentPowers and ClawHub sections separately; do not infer records from the unfiltered response.
Alternate fields are nested or renamedUse the extractor's recursive raw_values paths and alias-based normalized_values; retain every matching raw occurrence.
Plain page content is not valid JSONUse a BQL browser navigation to the API URL and parse document.body.innerText.
Unicode appears alteredConstruct q with encodeURIComponent, then compare decoded query and echoed_query.
Both source sections report total: 0Stop pagination and report the empty result set without fabricating metadata.
Query length is exactly 200 charactersTreat the request as accepted when navigation succeeds and query_length is 200.
Query length is 201 charactersExpect HTTP 422; record the failed goto status rather than treating it as a normal result.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=api.agentpowers.ai&task=search-agentpowers-skills