Skip to content
Back to skills

Browser Store Apis

ASecurity

Reference for browser extension store APIs for querying extension info, checking compatibility, and tracking submission status

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 2, 2026
securitytypescriptgobashazureapi

Works with

  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned June 2, 2026

npx -y skills add aRustyDev/agents --skill browser-store-apis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Browser Store Apis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Browser Store Apis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/arustydev-browser-store-apis/badge)](https://www.skillsdirectory.com/skills/arustydev-browser-store-apis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: browser-store-apis
description: Reference for browser extension store APIs for querying extension info, checking compatibility, and tracking submission status
tags: [browser-extension, api, chrome-web-store, firefox-addons, edge-addons]
---

# Browser Store APIs

Reference for browser extension store APIs used for querying extension info, checking compatibility, and tracking submission status.

## MCP Server: browser-store-api

The plugin includes an MCP server for store API integration.

### Configuration

```json
{
  "mcpServers": {
    "browser-store-api": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-browser-store-api"],
      "env": {
        "AMO_API_KEY": "${AMO_API_KEY}",
        "AMO_API_SECRET": "${AMO_API_SECRET}",
        "CHROME_WEBSTORE_CLIENT_ID": "${CHROME_WEBSTORE_CLIENT_ID}",
        "CHROME_WEBSTORE_CLIENT_SECRET": "${CHROME_WEBSTORE_CLIENT_SECRET}",
        "CHROME_WEBSTORE_REFRESH_TOKEN": "${CHROME_WEBSTORE_REFRESH_TOKEN}"
      }
    }
  }
}
```

### Available Tools

| Tool | Description |
|------|-------------|
| `amo_get_extension` | Get extension info from Firefox Add-ons |
| `amo_get_versions` | List version history from AMO |
| `amo_check_compatibility` | Check Firefox version compatibility |
| `cws_get_extension` | Get extension info from Chrome Web Store |
| `cws_get_reviews` | Get user reviews and ratings |
| `cws_check_status` | Check publication/review status |

## Firefox Add-ons API (AMO)

### Authentication

```bash
# Generate API credentials at:
# https://addons.mozilla.org/developers/addon/api/key/

export AMO_API_KEY="user:12345678:123"
export AMO_API_SECRET="your-api-secret"
```

### API Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v5/addons/addon/{id}/` | GET | Get addon details |
| `/api/v5/addons/addon/{id}/versions/` | GET | List versions |
| `/api/v5/addons/search/` | GET | Search addons |
| `/api/v5/reviewers/addon/{id}/` | GET | Review information |
| `/api/v5/accounts/profile/` | GET | Account info |

### Extension Info Request

```bash
# Get extension by slug or ID
curl "https://addons.mozilla.org/api/v5/addons/addon/ublock-origin/" \
  -H "Authorization: JWT $AMO_JWT_TOKEN"
```

### Response Structure

```json
{
  "id": 123456,
  "guid": "uBlock0@example.com",
  "slug": "ublock-origin",
  "name": {
    "en-US": "uBlock Origin"
  },
  "current_version": {
    "version": "1.50.0",
    "files": [
      {
        "id": 7890,
        "created": "2024-01-15T12:00:00Z",
        "status": "public",
        "size": 1234567
      }
    ]
  },
  "ratings": {
    "average": 4.8,
    "count": 50000
  },
  "weekly_downloads": 500000
}
```

### Version Compatibility

```bash
# Check version compatibility
curl "https://addons.mozilla.org/api/v5/addons/addon/{id}/versions/{version}/"
```

```json
{
  "version": "1.50.0",
  "compatibility": {
    "firefox": {
      "min": "109.0",
      "max": "*"
    },
    "android": {
      "min": "109.0",
      "max": "*"
    }
  },
  "is_strict_compatibility_enabled": false
}
```

## Chrome Web Store API

### Authentication

```bash
# Create OAuth2 credentials at:
# https://console.cloud.google.com/apis/credentials

export CHROME_WEBSTORE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export CHROME_WEBSTORE_CLIENT_SECRET="your-client-secret"
export CHROME_WEBSTORE_REFRESH_TOKEN="your-refresh-token"
```

### API Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/chromewebstore/v1.1/items/{itemId}` | GET | Get item info |
| `/chromewebstore/v1.1/items/{itemId}` | PUT | Update item |
| `/chromewebstore/v1.1/items/{itemId}/publish` | POST | Publish item |
| `/chromewebstore/v1.1/items` | POST | Create new item |

### Get Access Token

```bash
# Exchange refresh token for access token
curl -X POST "https://oauth2.googleapis.com/token" \
  -d "client_id=$CHROME_WEBSTORE_CLIENT_ID" \
  -d "client_secret=$CHROME_WEBSTORE_CLIENT_SECRET" \
  -d "refresh_token=$CHROME_WEBSTORE_REFRESH_TOKEN" \
  -d "grant_type=refresh_token"
```

### Extension Info Request

```bash
curl "https://www.googleapis.com/chromewebstore/v1.1/items/$ITEM_ID?projection=DRAFT" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "x-goog-api-version: 2"
```

### Response Structure

```json
{
  "kind": "chromewebstore#item",
  "id": "abcdefghijklmnopqrstuvwxyz123456",
  "publicKey": "...",
  "uploadState": "SUCCESS",
  "crxVersion": "1.0.0",
  "itemError": []
}
```

### Upload New Version

```bash
curl -X PUT \
  "https://www.googleapis.com/upload/chromewebstore/v1.1/items/$ITEM_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "x-goog-api-version: 2" \
  -T extension.zip
```

### Publish Extension

```bash
curl -X POST \
  "https://www.googleapis.com/chromewebstore/v1.1/items/$ITEM_ID/publish" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "x-goog-api-version: 2" \
  -H "Content-Length: 0"
```

## Edge Add-ons API

### Authentication

Uses Azure AD authentication via Partner Center.

```bash
# Register app in Azure Portal
# Grant permissions to Partner Center API

export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
```

### API Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/products/{productId}` | GET | Get product info |
| `/products/{productId}/submissions` | GET | List submissions |
| `/products/{productId}/submissions` | POST | Create submission |

### Get Token

```bash
curl -X POST \
  "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
  -d "client_id=$AZURE_CLIENT_ID" \
  -d "client_secret=$AZURE_CLIENT_SECRET" \
  -d "scope=https://api.partner.microsoft.com/.default" \
  -d "grant_type=client_credentials"
```

## Status Tracking

### Submission States

| Store | States |
|-------|--------|
| AMO | `pending`, `reviewing`, `approved`, `rejected` |
| Chrome | `PENDING`, `PUBLISHED`, `REJECTED`, `SUSPENDED` |
| Edge | `InProgress`, `Published`, `Failed` |

### Polling for Status

```typescript
async function pollSubmissionStatus(
  store: 'amo' | 'chrome' | 'edge',
  extensionId: string,
  maxAttempts: number = 60,
  intervalMs: number = 60000
): Promise<string> {
  for (let i = 0; i < maxAttempts; i++) {
    const status = await getSubmissionStatus(store, extensionId);

    if (isTerminalState(status)) {
      return status;
    }

    await sleep(intervalMs);
  }

  throw new Error('Status check timed out');
}

function isTerminalState(status: string): boolean {
  const terminal = [
    'approved', 'rejected',      // AMO
    'PUBLISHED', 'REJECTED',     // Chrome
    'Published', 'Failed'        // Edge
  ];
  return terminal.includes(status);
}
```

## Version Checking

### Compare Versions

```typescript
function compareVersions(v1: string, v2: string): number {
  const parts1 = v1.split('.').map(Number);
  const parts2 = v2.split('.').map(Number);

  for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
    const p1 = parts1[i] || 0;
    const p2 = parts2[i] || 0;

    if (p1 > p2) return 1;
    if (p1 < p2) return -1;
  }

  return 0;
}

function isNewerVersion(current: string, published: string): boolean {
  return compareVersions(current, published) > 0;
}
```

### Check All Stores

```typescript
interface StoreVersions {
  amo: string | null;
  chrome: string | null;
  edge: string | null;
}

async function checkAllStoreVersions(
  extensionIds: { amo?: string; chrome?: string; edge?: string }
): Promise<StoreVersions> {
  const [amo, chrome, edge] = await Promise.all([
    extensionIds.amo ? getAMOVersion(extensionIds.amo) : null,
    extensionIds.chrome ? getChromeVersion(extensionIds.chrome) : null,
    extensionIds.edge ? getEdgeVersion(extensionIds.edge) : null
  ]);

  return { amo, chrome, edge };
}
```

## Rate Limits

| Store | Limit | Window |
|-------|-------|--------|
| AMO | 100 requests | per minute |
| Chrome Web Store | 2000 requests | per day |
| Edge Partner Center | 500 requests | per minute |

### Retry Strategy

```typescript
async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries: number = 3,
  baseDelayMs: number = 1000
): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      const isRateLimit = error.status === 429;
      const delay = isRateLimit
        ? parseInt(error.headers['retry-after'] || '60') * 1000
        : baseDelayMs * Math.pow(2, i);

      await sleep(delay);
    }
  }
  throw new Error('Max retries exceeded');
}
```

## Common Use Cases

### Check for Updates Needed

```typescript
async function checkUpdatesNeeded(
  manifestVersion: string,
  extensionIds: { amo?: string; chrome?: string; edge?: string }
): Promise<{ store: string; needsUpdate: boolean }[]> {
  const storeVersions = await checkAllStoreVersions(extensionIds);

  return Object.entries(storeVersions)
    .filter(([_, version]) => version !== null)
    .map(([store, version]) => ({
      store,
      needsUpdate: isNewerVersion(manifestVersion, version!)
    }));
}
```

### Submit to All Stores

```typescript
async function submitToAllStores(
  zipPath: string,
  extensionIds: { amo: string; chrome: string; edge: string }
): Promise<{ store: string; success: boolean; error?: string }[]> {
  const results = await Promise.allSettled([
    submitToAMO(zipPath, extensionIds.amo),
    submitToChrome(zipPath, extensionIds.chrome),
    submitToEdge(zipPath, extensionIds.edge)
  ]);

  return [
    { store: 'amo', ...resultToStatus(results[0]) },
    { store: 'chrome', ...resultToStatus(results[1]) },
    { store: 'edge', ...resultToStatus(results[2]) }
  ];
}
```

## Related Resources

- **store-submission-reviewer agent**: Pre-submission compliance checks
- **extension-store-submission skill**: Submission process guides
- **validate-extension command**: Local validation before submission

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…