PeekPanda markpeekpandaDocumentationFor AI ↗Open app

PeekPanda docs

Add ASO keywords

Track keywords on an ASO app and return the updated workstation.

Download Markdown ↓
POST/v1/aso/apps/{appId}/keywords
Auth Bearer API credential or OAuth access tokenScope content:writeMCP add_aso_keywords

Request

Adds queries (max 100 per app). Source is `manual`, `suggested`, `extracted`, or `hint`. The service returns the updated workstation after queuing stale-query refresh.

curl --request POST 'https://api.peekpanda.com/v1/aso/apps/11111111-1111-4111-8111-111111111111/keywords' \
  --header "Authorization: Bearer $PEEKPANDA_TOKEN" \
  --header 'x-genviral-tenancy: personal' \
  --header 'content-type: application/json' \
  --data '{"queries":["calorie tracker"],"source":"manual"}'

Response

addKeywords returns asoWorkstationSchema, the same shape as GET /v1/aso/apps/{appId}.

{
  "app": {
    "storeId": "0000000000",
    "name": "Example Calorie Tracker",
    "iconUrl": null,
    "developerName": "Example Labs",
    "primaryGenre": "Health & Fitness",
    "rating": 4.7,
    "ratingCount": 12450,
    "inCatalogue": true,
    "id": "11111111-1111-4111-8111-111111111111",
    "role": "mine",
    "createdAt": "2026-09-06T00:00:00.000Z",
    "lastRefreshedAt": "2026-09-06T00:00:00.000Z",
    "keywordCount": 1
  },
  "refresh": {
    "state": "fresh",
    "lastRefreshedAt": "2026-09-06T00:00:00.000Z",
    "nextAllowedAt": "2026-09-06T01:00:00.000Z",
    "staleQueryCount": 0,
    "activeJobId": null,
    "budget": {
      "usedToday": 12,
      "dailyLimit": 2500,
      "userRefreshesToday": 1,
      "userDailyLimit": 40
    }
  },
  "profile": {
    "positionKind": "observed_search_api_position",
    "storeId": "0000000000",
    "coverage": {
      "queriesCollected": 0,
      "queriesMatched": 0,
      "country": "us",
      "language": "en_us",
      "source": "itunes_search",
      "latestObservedAt": null,
      "observationCount": 0
    },
    "summary": {
      "top3": 0,
      "top10": 0,
      "top50": 0,
      "bestPosition": null,
      "medianPosition": null
    },
    "keywords": [],
    "rivals": [],
    "keywordIdeas": [],
    "insights": [
      {
        "kind": "coverage_gap",
        "title": "Not in the collected query set yet",
        "detail": "This app did not appear in any collected queries.",
        "keywords": [],
        "catalogueStoreId": null
      }
    ]
  },
  "keywords": [
    {
      "query": "calorie tracker",
      "position": 4,
      "trackedKeywordId": "22222222-2222-4222-8222-222222222222",
      "source": "manual",
      "observedAt": "2026-09-06T00:00:00.000Z",
      "isStale": false,
      "resultCount": 1,
      "apps": [
        {
          "storeId": "0000000000",
          "position": 4,
          "name": "Example Calorie Tracker",
          "isSubject": true,
          "inCatalogue": true
        }
      ],
      "history": [
        {
          "observedAt": "2026-09-06T00:00:00.000Z",
          "position": 4
        }
      ],
      "difficulty": {
        "score": 40,
        "method": "page_one_median_rating_count",
        "medianRatingCount": 8000,
        "sampleSize": 8
      },
      "demand": {
        "score": 90,
        "method": "apple_search_hints",
        "hintRank": 2,
        "variantCount": 3,
        "observedAt": "2026-09-06T00:00:00.000Z"
      }
    }
  ],
  "suggestions": [
    {
      "query": "calorie counter",
      "source": "hint",
      "reason": "Apple suggests it",
      "position": null,
      "appCount": null,
      "isTracked": false
    }
  ],
  "trackedCompetitors": []
}

Parameters

NameInTypeRequiredDescription
appIdpathuuidYesTracked ASO app id.
queriesbodystring[]YesKeywords to track; max 100 per app.
sourcebodymanual | suggested | extracted | hintYesHow the keywords were chosen.

Known errors

400invalid_request for an invalid filter, identity or limit.
401authentication_required for a missing or invalid credential.
402subscription_required when access is not entitled.
403authorization_required for a missing scope or unavailable preview access.
404not_found when the record is outside the accessible catalogue.
429rate_limited; honor Retry-After when present.
409conflict when the write would duplicate an exclusive row.

Source

Apple public Search + Search hints. Difficulty from page-one rating counts Apple returns (page_one_median_rating_count: median page-one ratingCount, log10 scale, 1M ratings = 100). Demand is autocomplete order from apple_search_hints (rank + variant count), not volume and not Apple Ads popularity. Apple Ads Insights is not wired. Positions are observed_search_api_position from itunes.apple.com/search us/en_us.

Refresh

Snapshots younger than 24 hours are served from storage; search hints are reused for 7 days. Trigger/worker drains aso_refresh_job under the shared 4s pacer (2,500 Apple calls per UTC day). App refresh cooldown is 60 minutes. Users may start 40 refreshes per UTC day. Caps: 25 tracked apps, 100 keywords per app, 200 queries per job.