Get market signals
Read chart, paid-ad, organic and keyword signals for up to 600 iOS apps in one batch.
Download Markdown ↓GEThttps://api.peekpanda.com/v1/market/signals
Request
Send country and storeIds as query parameters. storeIds is one comma-separated value of numeric Apple store IDs; MCP clients may send an array instead. This GET never starts collection.
Parameters
countryquery^[a-z]{2}$NoApple storefront as two lowercase letters. Defaults to us.storeIdsquerycomma-separated numeric IDs, 1–600 uniqueYesApple store IDs to annotate, such as the rows of one chart page. Duplicates are removed before the 600 limit applies.Response
The response echoes the country and the eight weekly dates, says when keyword positions were observed and when organic views were counted, and lists apps keyed by storeId. Look entries up by storeId, not by position. Each app carries the name and 128px icon the market boards print; both are null when no stored fact names the app. placement, paid, organic and keywords are each null when that stream was never collected for the app, never zero. paidCollection says when the app’s paid ads were last collected: freshness is never (no collection has finished, so a null paid signal says nothing about the app’s ads), stale (the last collection is more than two days old) or fresh, the same words boards use, and lastCollectedAt is null until one has finished. A null paid signal with fresh collection means the app ran no ads PeekPanda could find. The second app in the example has no collected ads or organic posts.
Response fields
countrystringweeks[]string[]keywordsObservedAtstringorganicViewsCountedAtstringapps[].storeIdstringapps[].placement.ranknumberapps[].placement.previousRanknumberapps[].placement.chartTypestringapps[].placement.categoryIdstringapps[].placement.categoryNamestringapps[].placement.daystringapps[].paid.totalAdsnumberapps[].paid.liveAdsnumberapps[].paid.startedLast7Daysnumberapps[].paid.medianDaysLivenumberapps[].paid.longestDaysLivenumberapps[].paid.formatsobjectapps[].paid.topCallToActionstringapps[].paid.destinationsobjectapps[].paid.weeklyStarts[]number[]apps[].organic.matchedPostsnumberapps[].organic.viewsnumberapps[].organic.medianViewsnumberapps[].organic.bestPostViewsnumberapps[].organic.postsOverMillionnumberapps[].organic.newestPublishedAtstringapps[].organic.platformsobjectapps[].organic.matchedBystringapps[].keywords.rankednumberapps[].keywords.top1numberapps[].keywords.top3numberapps[].keywords.top10numberapps[].keywords.top50numberapps[].keywords.bestobjectapps[].keywords.top[].querystringapps[].keywords.top[].positionnumberapps[].keywords.top[].popularitynumberapps[].keywords.top[].popularityEstimatenullapps[].namestringapps[].iconUrlstringapps[].paidCollection.freshnessstringapps[].paidCollection.lastCollectedAtstringAuthentication
Requires Bearer API credential or OAuth access token. Scope context:read. MCP calls get_market with action signals.
Errors
400invalid_request for an unknown query parameter, an invalid country, or storeIds that are missing, non-numeric or more than 600 unique IDs.401authentication_required for a missing or invalid credential.402subscription_required when access is not entitled.403authorization_required for a missing context:read scope or unavailable preview access.429rate_limited; wait for the Retry-After seconds, then send the same request again.MCP request
Call get_market with action signals. Path fields go in params, filters in query, and a write body in body.
{
"name": "get_market",
"arguments": {
"request": {
"action": "signals",
"query": {
"storeIds": "<storeIds>"
}
}
}
}
Source
placement is the best rank across every stored App Store chart of the storefront on the latest chart day, with the previous day’s rank. Paid ads are collected per chosen app, so an app without ads has not been collected. An ad counts for the app its own verified App Store link names, or for the app its proven advertiser page runs ads for, web funnels and Google Play links included; the paid pulse counts the same ads. destinations splits them into App Store, Play Store and web-funnel ads, and only App Store ads are counted as appStore. "Last 7 days" and run lengths are UTC calendar days. Its paid signal is null. Organic posts are matched by product name, not account ownership, and their views are as last counted. organicViewsCountedAt says when. Keyword positions are observed App Store search result positions, not search volume. Each signals keyword carries popularity, Apple's weekly search popularity (1 to 100), or null when Apple reports nothing. Where Apple reports nothing for a US keyword, popularityEstimate carries PeekPanda's own tier (very_low, low, medium or high) with estimatedAt and the modelTrainedAt of the weekly model behind it, never a number on Apple's scale. popularityEstimate is null whenever popularity is set and on every non-US storefront. Neither is a search count.
Refresh
This GET reads the same stored evidence as GET /v1/market/overview and never starts collection. To ask for paid-ad or organic evidence on one app, record a data request for that competitor.
Rate limits
Market reads share the standard read budget of 60 requests per minute with every other PeekPanda read. During the preview the count is kept per client network address, not per plan, and it resets at the end of each one-minute window. A 429 rate_limited response carries Retry-After when the server can say how long to wait: wait that many seconds, then send the same request again. Every call also counts toward your plan's daily API and MCP allowance: 30 calls a day on Peek and 1,000 on Panda, shared by every key and MCP connection on the plan and reset at 00:00 UTC. Past it, calls answer 429 daily_call_limit until the reset. Stored reads do not use your refresh allowance.
Batches
This read has no cursor. Send at most 600 unique store IDs per request and split a longer list into batches of 600. Each app carries at most 5 top keywords, and every weekly series has exactly 8 Monday-start weeks, oldest first, ending with the current, partial week.
AI agent or LLM? Read this page as markdown