# Add a board item

Pin an App Store app, or save one paid ad, to a board.

## Contract status

Preview contract: these routes and tools are implemented in the shared contract, but the public host, customer API access and OAuth flow have not been deployment verified.

## Endpoint: POST /v1/boards/{boardId}/items

- Method: `POST`
- Path: `/v1/boards/{boardId}/items`
- Authentication: Bearer API credential or OAuth access token
- Required scope: `content:write`
- MCP tool: `manage_boards`
- MCP action: `add_item`

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `boardId` | path | uuid | yes | Board id. |
| `kind` | body | 'app' | 'ad' | yes | What to add. |
| `storeId` | body | string | yes | For an app: numeric App Store id of a catalogue app. |
| `platform` | body | 'meta' | 'tiktok' | yes | For an ad: advertising platform. |
| `archiveId` | body | string | yes | For an ad: archive id. |
| `note` | body | string | null | yes | Optional note, up to 500 characters. |

## Known errors

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

## Request

Repeating the same app or ad returns the existing item. Pinning never watches the app or starts collection. At most 500 items per board.

```
curl --request POST 'https://api.peekpanda.com/v1/boards/66666666-6666-4666-8666-666666666666/items' \
  --header "Authorization: Bearer $PEEKPANDA_TOKEN" \
  --header 'x-genviral-tenancy: personal' \
  --header 'content-type: application/json' \
  --data '{"kind":"app","storeId":"0000000000"}'
```

## MCP request

Call manage_boards with action add_item. Path fields go in params, filters in query, and a write body in body.

```
{
  "name": "manage_boards",
  "arguments": {
    "request": {
      "action": "add_item",
      "params": {
        "boardId": "<boardId>"
      }
    }
  }
}

```

## Response

The board item. An app item carries its stored evidence and the caller's watchlist stamps.

```
{
  "id": "77777777-7777-4777-8777-777777777777",
  "kind": "app",
  "storeId": "0000000000",
  "name": "Example Recipe Planner",
  "iconUrl": null,
  "note": null,
  "addedByUserId": "99999999-9999-4999-8999-999999999999",
  "createdAt": "2026-09-06T00:00:00.000Z",
  "watch": null,
  "evidence": {
    "liveAds": 4,
    "newAdsThisWeek": 1,
    "savedAdsOnBoard": 1,
    "inCatalogue": true
  }
}

```

## Source

Boards are the caller's own organization, stored in PeekPanda. Pinned apps carry the listing name and icon as pinned; evidence counts are stored paid-ad observations.

## Refresh

Board reads and writes never call a provider or start collection. Pinning an app does not watch it; watching stays on the ASO tracked-app list.
